我如何编写两个函数,如果它以指定的字符/字符串开头或以指定的字符串结尾,那么它们将接受字符串并返回?
例如:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
我如何编写两个函数,如果它以指定的字符/字符串开头或以指定的字符串结尾,那么它们将接受字符串并返回?
例如:
$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开头吗?”这样的问题,所以你要做出决定,但要确保你的决定是好的。
其他回答
我会这样做
function startWith($haystack,$needle){
if(substr($haystack,0, strlen($needle))===$needle)
return true;
}
function endWith($haystack,$needle){
if(substr($haystack, -strlen($needle))===$needle)
return true;
}
专注于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不迭代整个字符串(但即使在这种情况下),这一点都不方便。
到目前为止,所有的答案似乎都做了大量不必要的工作、strlen计算、字符串分配(substr)等。“strpos”和“stripos”函数返回$haystack中$needle第一次出现的索引:
function startsWith($haystack,$needle,$case=true)
{
if ($case)
return strpos($haystack, $needle, 0) === 0;
return stripos($haystack, $needle, 0) === 0;
}
function endsWith($haystack,$needle,$case=true)
{
$expectedPosition = strlen($haystack) - strlen($needle);
if ($case)
return strrpos($haystack, $needle, 0) === $expectedPosition;
return strripos($haystack, $needle, 0) === $expectedPosition;
}
PHP 8更新
PHP 8包含了新的str_starts_with和str_ends_with函数,它们最终为这个问题提供了一个高效便捷的解决方案:
$str = "beginningMiddleEnd";
if (str_starts_with($str, "beg")) echo "printed\n";
if (str_starts_with($str, "Beg")) echo "not printed\n";
if (str_ends_with($str, "End")) echo "printed\n";
if (str_ends_with($str, "end")) echo "not printed\n";
该特性的RFC提供了更多信息,同时也讨论了明显(但不那么明显)用户区域实现的优点和问题。
这个问题已经有很多答案,但在某些情况下,你可以选择比所有答案都简单的答案。如果要查找的字符串是已知的(硬编码的),则可以使用正则表达式而不使用任何引号等。
检查字符串是否以“ABC”开头:
preg_match('/^ABC/', $myString); // "^" here means beginning of string
以“ABC”结尾:
preg_match('/ABC$/', $myString); // "$" here means end of string
在我的简单示例中,我想检查字符串是否以斜杠结尾:
preg_match('#/$#', $myPath); // Use "#" as delimiter instead of escaping slash
优点:由于它非常简短和简单,您不必像上面所示那样定义函数(例如endsWith())。
但是,这并不是每一种情况的解决方案,只是一种非常具体的解决方案。