我如何编写两个函数,如果它以指定的字符/字符串开头或以指定的字符串结尾,那么它们将接受字符串并返回?

例如:

$str = '|apples}';

echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true

当前回答

做得更快:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

这一行比较字符串的第一个字符,可以使false case会立即返回,因此会进行许多比较速度快得多(测量时快7倍)。在真实的情况下,你几乎没有为这条线付出任何性能代价,所以我认为这是值得的。(此外,在实践中,当您为一个特定的起始块测试多个字符串时,大多数比较都会失败,因为在典型的情况下,您正在寻找一些东西。)

注意:@Tino下面评论中的bug已经修复

对于字符串与整数

如果要强制字符串比较(即,期望startsWith(“1234”,12)为true),则需要一些类型转换:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    $haystack = (string)$haystack;
    $needle   = (string)$needle;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

我不认为这是必要的,但这是一个有趣的边缘案例,导致了诸如“布尔值真以t开头吗?”这样的问题,所以你要做出决定,但要确保你的决定是好的。

其他回答

mpen给出的答案非常彻底,但不幸的是,提供的基准有一个非常重要且有害的监督。

因为针和草堆中的每个字节都是完全随机的,所以针-草堆对在第一个字节上不同的概率为99.609375%,这意味着平均而言,100000对中的大约99609对在第一字节上不同。换言之,基准测试严重偏向于显式检查第一个字节的startswith实现,正如strncmp_startswith2所做的那样。

如果测试生成循环按如下方式实现:

echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
    if($i % 2500 === 0) echo '.';

    $haystack_length = random_int(1, 7000);
    $haystack = random_bytes($haystack_length);

    $needle_length = random_int(1, 3000);
    $overlap_length = min(random_int(0, $needle_length), $haystack_length);
    $needle = ($needle_length > $overlap_length) ?
        substr($haystack, 0, $overlap_length) . random_bytes($needle_length - $overlap_length) :
        substr($haystack, 0, $needle_length);

    $test_cases[] = [$haystack, $needle];
}
echo " done!<br />";

基准测试结果讲述了一个略有不同的故事:

strncmp_startswith: 223.0 ms
substr_startswith: 228.0 ms
substr_compare_startswith: 238.0 ms
strncmp_startswith2: 253.0 ms
strpos_startswith: 349.0 ms
preg_match_startswith: 20,828.7 ms

当然,这个基准可能仍然不是完全无偏的,但它也测试了当给定部分匹配的针时算法的效率。

为什么不采取以下措施?

//How to check if a string begins with another string
$haystack = "valuehaystack";
$needle = "value";
if (strpos($haystack, $needle) === 0){
    echo "Found " . $needle . " at the beginning of " . $haystack . "!";
}

输出:

在valuehaystack的开头找到值!

请记住,如果在干草堆中没有找到针,strpos将返回false,如果且仅当在索引0处找到针时(即开头),strpos将返回0。

以下是结尾:

$haystack = "valuehaystack";
$needle = "haystack";

//If index of the needle plus the length of the needle is the same length as the entire haystack.
if (strpos($haystack, $needle) + strlen($needle) === strlen($haystack)){
    echo "Found " . $needle . " at the end of " . $haystack . "!";
}

在这种情况下,不需要函数startsWith()作为

(strpos($stringToSearch, $doesItStartWithThis) === 0)

将准确返回true或false。

奇怪的是,这么简单,所有的野生函数都在这里泛滥。

专注于startswith,如果您确定字符串不为空,那么在比较之前,在第一个字符、strlen等上添加一个测试会加快速度:

function startswith5b($haystack, $needle) {
    return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
}

不知怎么的,速度快了(20%-30%)。添加另一个字符测试,如$haystack{1}==$needle{1},似乎并不能加快速度,甚至可能会减慢速度。

==似乎比==条件运算符(a)?b: c似乎比如果(a)b更快;否则c;


对于那些问“为什么不使用strpos?”并称其他解决方案为“不必要的工作”的人


strpos速度很快,但它不是这项工作的正确工具。

为了理解,这里有一个小模拟作为示例:

Search a12345678c inside bcdefga12345678xbbbbb.....bbbbba12345678c

电脑在里面做什么?

    With strccmp, etc...

    is a===b? NO
    return false



    With strpos

    is a===b? NO -- iterating in haysack
    is a===c? NO
    is a===d? NO
    ....
    is a===g? NO
    is a===g? NO
    is a===a? YES
    is 1===1? YES -- iterating in needle
    is 2===3? YES
    is 4===4? YES
    ....
    is 8===8? YES
    is c===x? NO: oh God,
    is a===1? NO -- iterating in haysack again
    is a===2? NO
    is a===3? NO
    is a===4? NO
    ....
    is a===x? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    is a===b? NO
    ...
    ... may many times...
    ...
    is a===b? NO
    is a===a? YES -- iterating in needle again
    is 1===1? YES
    is 2===3? YES
    is 4===4? YES
    is 8===8? YES
    is c===c? YES YES YES I have found the same string! yay!
    was it at position 0? NOPE
    What you mean NO? So the string I found is useless? YEs.
    Damn.
    return false

假设strlen不迭代整个字符串(但即使在这种情况下),这一点都不方便。

做得更快:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

这一行比较字符串的第一个字符,可以使false case会立即返回,因此会进行许多比较速度快得多(测量时快7倍)。在真实的情况下,你几乎没有为这条线付出任何性能代价,所以我认为这是值得的。(此外,在实践中,当您为一个特定的起始块测试多个字符串时,大多数比较都会失败,因为在典型的情况下,您正在寻找一些东西。)

注意:@Tino下面评论中的bug已经修复

对于字符串与整数

如果要强制字符串比较(即,期望startsWith(“1234”,12)为true),则需要一些类型转换:

function startsWith($haystack,$needle) {
    if($needle==="") return true;
    $haystack = (string)$haystack;
    $needle   = (string)$needle;
    if($haystack[0]<>$needle[0]) return false; // ------------------------- speed boost!
    return (0===substr_compare($haystack,$needle,0,strlen($needle)));
}

我不认为这是必要的,但这是一个有趣的边缘案例,导致了诸如“布尔值真以t开头吗?”这样的问题,所以你要做出决定,但要确保你的决定是好的。

这可能奏效

function startsWith($haystack, $needle) {
     return substr($haystack, 0, strlen($needle)) == $needle;
}

资料来源:https://stackoverflow.com/a/4419658