【问题标题】:How to check if a string starts with "_" in PHP? [duplicate]如何在PHP中检查字符串是否以“_”开头? [复制]
【发布时间】:2010-12-30 00:59:26
【问题描述】:

示例:我有一个$variable = "_foo",我想绝对确保$variable 不以下划线"_" 开头。我怎样才能在 PHP 中做到这一点?是否可以访问字符串后面的 char 数组?

【问题讨论】:

  • 有人发布了一个使用正则表达式的答案,该答案令人惊讶地被否决了 4 次,理由是它“不适合使用正则表达式”。由于同行压力,该答案的所有者将其删除。如果输入验证不是正则表达式的好用,我不知道是什么。在此用例中,性能不是的重要因素。如果发帖人想取消删除正则表达式答案,我会很高兴地投票。
  • @Asaph:正则表达式被过度使用和过度推荐。对于这个用例,它们完全过度杀戮。我看不出您如何声称性能不是一个重要因素。你当然不会备份它。
  • 恐怕我同意@LightnessRacesinOrbit 的观点,对于不了解 PHP 基础的人来说,正则表达式是一种矫枉过正、人为的回答。我认为正则表达式回答者刚刚去了,“哎呀!” :)
  • @HenrikErlandsson 正则表达式和非正则表达式解决方案都有效;任何性能问题都应作为警告添加到正文中或在 cmets 中指出。 OP 并不是唯一从他们的问题中受益的人。由读者自行决定采用哪种解决方案。
  • @rath 任何没有副作用或直接错误的过于复杂的答案都是有效的,但这并不意味着它是一个好的答案。特别是因为 OP 还询问了 char 数组。

标签: php


【解决方案1】:
$variable[0] != "_"

它是如何工作的?

在 PHP 中,您可以使用数组索引表示法获取字符串的特定字符。 $variable[0] 是字符串的第一个字符(如果 $variable 是字符串)。

【讨论】:

  • 解释为什么这会很棒,但无论如何+1。
  • 你去。为你添加了解释。
  • 在访问第一个字节之前,您应该测试字符串是否至少有一个字节长。
  • 令人惊讶的是人们会要求解释而不是查阅手册。
  • Python 很久以前就已经有了这种访问子字符串的语法。
【解决方案2】:

您可以查看 php 中的 substr 函数并以这种方式获取第一个字符:

http://php.net/manual/en/function.substr.php

if (substr('_abcdef', 0, 1) === '_') { ... }

【讨论】:

【解决方案3】:

由于有人提到效率,我出于好奇对迄今为止给出的函数进行了基准测试:

function startsWith1($str, $char) {
    return strpos($str, $char) === 0;
}
function startsWith2($str, $char) {
    return stripos($str, $char) === 0;
}
function startsWith3($str, $char) {
    return substr($str, 0, 1) === $char;
}
function startsWith4($str, $char){
    return $str[0] === $char;
}
function startsWith5($str, $char){
    return (bool) preg_match('/^' . $char . '/', $str);
}
function startsWith6($str, $char) {
    if (is_null($encoding)) $encoding = mb_internal_encoding();
    return mb_substr($str, 0, mb_strlen($char, $encoding), $encoding) === $char;
}

这是我平均每台运行 100.000 次的 DualCore 机器上的结果

// Testing '_string'
startsWith1 took 0.385906934738
startsWith2 took 0.457293987274
startsWith3 took 0.412894964218
startsWith4 took 0.366240024567 <-- fastest
startsWith5 took 0.642996072769
startsWith6 took 1.39859509468

// Tested "string"
startsWith1 took 0.384965896606
startsWith2 took 0.445554971695
startsWith3 took 0.42377281189
startsWith4 took 0.373164176941 <-- fastest
startsWith5 took 0.630424022675
startsWith6 took 1.40699005127

// Tested 1000 char random string [a-z0-9]
startsWith1 took 0.430691003799
startsWith2 took 4.447286129
startsWith3 took 0.413349866867
startsWith4 took 0.368592977524 <-- fastest
startsWith5 took 0.627470016479
startsWith6 took 1.40957403183

// Tested 1000 char random string [a-z0-9] with '_' prefix
startsWith1 took 0.384054899216
startsWith2 took 4.41522812843
startsWith3 took 0.408898115158
startsWith4 took 0.363884925842 <-- fastest
startsWith5 took 0.638479948044
startsWith6 took 1.41304707527

如您所见,将 haystack 视为数组以找出第一个位置的字符是总是最快的解决方案。无论字符串长度如何,它也始终以相同的速度执行。当字符串不以前缀开头时,使用strpossubstr 短字符串快,但长字符串慢。差异是无关紧要的。 stripos 对于长字符串难以置信慢。 preg_match 无论字符串长度如何,性能几乎相同,但速度却很一般。 mb_substr 解决方案性能最差,但可能更可靠。

鉴于这些数字是针对 100.000 次运行的,很明显我们所说的是每次调用 0.0000x 秒。为效率选择一个而不是另一个是毫无价值的微优化,除非您的应用正在以 startsWith 为生。

【讨论】:

  • +1:坦率地说,我真的很惊讶preg_match 这么快。
  • 我喜欢性能测试和结果。 +1。
【解决方案4】:

这是您不关心性能的最简单的答案:

if (strpos($string, '_') === 0) {
    # code
}

如果 strpos 返回 0,则意味着您要查找的内容从字符 0 开始,即字符串的开头。

这里有详细记录:http://uk3.php.net/manual/en/function.strpos.php

(PS$string[0] === '_'是最佳答案)

【讨论】:

    【解决方案5】:
    function starts_with($s, $prefix){
        // returns a bool
        return strpos($s, $prefix) === 0;
    }
    
    starts_with($variable, "_");
    

    【讨论】:

    • +1 所有其他解决方案都对空字符串输入无效。
    • 低效 - 如果没有立即找到前缀,则扫描整个字符串。
    • 来自substr 手册:“如果字符串长度小于或等于起始字符,将返回 FALSE。”所以 substr($foo,0,1) 可以完美地处理空字符串。
    • 正如 Seva 所说,这实在是太低效了。如果我必须使用一个函数,我会使用 substr 而不是 strpos
    • @Wim:感谢您指出这一点。又一个 PHP 的例子具有不直观但方便的行为。
    【解决方案6】:

    这里有一个更好的开头函数:

    function mb_startsWith($str, $prefix, $encoding=null) {
        if (is_null($encoding)) $encoding = mb_internal_encoding();
        return mb_substr($str, 0, mb_strlen($prefix, $encoding), $encoding) === $prefix;
    }
    

    【讨论】:

    • 这个过度工程解决了什么问题?
    • 他正在尝试检查下划线,而不是重音符号。
    • @just someone:它允许在考虑多字节字符串的同时测试任意前缀。
    【解决方案7】:

    以 pinusnegra 的回答为基础,并回应 Gumbo 对该回答的评论:

    function has_leading_underscore($string) {
    
        return $string[0] === '_';
    
    }
    

    在 PHP 5.3.0 上运行,即使不检查字符串长度是否至少为 1 个字符,以下内容也可以正常工作并返回预期值:

    echo has_leading_underscore('_somestring').', ';
    echo has_leading_underscore('somestring').', ';
    echo has_leading_underscore('').', ';
    echo has_leading_underscore(null).', ';
    echo has_leading_underscore(false).', ';
    echo has_leading_underscore(0).', ';
    echo has_leading_underscore(array('_foo', 'bar'));
    
    /*
     * output: true, false, false, false, false, false, false
     */
    

    我不知道其他版本的PHP会如何反应,但是如果它们都可以工作,那么这种方法可能比substr路由更有效。

    【讨论】:

    • 你为什么使用字符串'yes'/'no'?该语言具有布尔值。
    • @Chad 我不记得了。如果我不得不猜测,那是因为我直接打印了结果,并且出于某种原因,我想阅读是/否而不是真/假。你是对的,使用布尔值会更好,另外它会简化逻辑。我会改的。
    猜你喜欢
    • 2011-02-16
    • 2010-09-21
    • 2014-11-28
    • 2019-08-24
    • 2015-04-15
    • 1970-01-01
    • 2010-12-18
    • 2012-02-09
    • 2012-02-06
    相关资源
    最近更新 更多