我该如何编写两个函数,能够接受一个字符串并返回它是否以指定的字符/字符串开头或结尾?
比如:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
自PHP 8.0起,您可以使用
str_starts_with
手册和
str_ends_with
手册
echo str_starts_with($str, '|');
function startsWith( $haystack, $needle ) {
$length = strlen( $needle );
return substr( $haystack, 0, $length ) === $needle;
}
function endsWith( $haystack, $needle ) {
$length = strlen( $needle );
if( !$length ) {
return true;
}
return substr( $haystack, -$length ) === $needle;
}
return substr($haystack, -strlen($needle))===$needle;
。 - Rok Kralj$needle
不为空时才执行。 - Ja͢ck$length
作为 substr
的第三个参数传递来完全避免使用 if
:return (substr($haystack, -$length, $length);
。这种方法处理 $length == 0
的情况,将返回空字符串而不是整个 $haystack
。 - mxxk您可以使用substr_compare
函数来检查字符串是否以某个特定的前缀或后缀开头:
function startsWith($haystack, $needle) {
return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
function endsWith($haystack, $needle) {
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
这应该是 PHP 7 上最快的解决方案之一(基准测试脚本)。针对8KB的大字符串、不同长度的子串以及完整匹配、部分匹配和未匹配的情况进行了测试。 strncmp
在匹配开头时略快,但无法检查结尾。
xxxyyy
,needle = yyy
,使用 strrpos
开始搜索时从第一个 x
开始。现在我们没有成功匹配(找到了 x
而不是 y
),并且我们不能再向后移动了(我们已经在字符串的开头),搜索立即失败。关于使用 !== false
-- 在上面的示例中,strrpos
将返回 0 或 false,而不是其他值。同样,strpos
在上面的示例中可以返回 $temp
(预期位置)或 false。我选择使用 !== false
是为了一致性,但你也可以分别在函数中使用 === 0
和 === $temp
。 - Salman A更新于2016年8月23日
function substr_startswith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) === $needle;
}
function preg_match_startswith($haystack, $needle) {
return preg_match('~' . preg_quote($needle, '~') . '~A', $haystack) > 0;
}
function substr_compare_startswith($haystack, $needle) {
return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
function strpos_startswith($haystack, $needle) {
return strpos($haystack, $needle) === 0;
}
function strncmp_startswith($haystack, $needle) {
return strncmp($haystack, $needle, strlen($needle)) === 0;
}
function strncmp_startswith2($haystack, $needle) {
return $haystack[0] === $needle[0]
? strncmp($haystack, $needle, strlen($needle)) === 0
: false;
}
echo 'generating tests';
for($i = 0; $i < 100000; ++$i) {
if($i % 2500 === 0) echo '.';
$test_cases[] = [
random_bytes(random_int(1, 7000)),
random_bytes(random_int(1, 3000)),
];
}
echo "done!\n";
$functions = ['substr_startswith', 'preg_match_startswith', 'substr_compare_startswith', 'strpos_startswith', 'strncmp_startswith', 'strncmp_startswith2'];
$results = [];
foreach($functions as $func) {
$start = microtime(true);
foreach($test_cases as $tc) {
$func(...$tc);
}
$results[$func] = (microtime(true) - $start) * 1000;
}
asort($results);
foreach($results as $func => $time) {
echo "$func: " . number_format($time, 1) . " ms\n";
}
(按速度排序,从快到慢)
strncmp_startswith2: 40.2 ms
strncmp_startswith: 42.9 ms
substr_compare_startswith: 44.5 ms
substr_startswith: 48.4 ms
strpos_startswith: 138.7 ms
preg_match_startswith: 13,152.4 ms
(按速度从快到慢排序)
strncmp_startswith2: 477.9 ms
strpos_startswith: 522.1 ms
strncmp_startswith: 617.1 ms
substr_compare_startswith: 706.7 ms
substr_startswith: 756.8 ms
preg_match_startswith: 10,200.0 ms
到目前为止所有的答案都做了很多不必要的工作,如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;
}
endsWith()
函数存在错误。
它的第一行应该是(去掉 -1):
$expectedPosition = strlen($haystack) - strlen($needle);
- Enrico Detomajson_decode()
的话,你应该强烈考虑像这样引用类似于strpos($haystack, "$needle", 0)
的needle。否则, strpos()
的[奇怪]默认行为可能会导致意外的结果:“如果needle不是一个字符串,则它将被转换为整数并作为字符的序值应用。” - quietmintPHP 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提供了更多信息,同时还讨论了明显(和不太明显)的用户空间实现的优点和问题。
function startsWith($haystack, $needle, $case = true) {
if ($case) {
return (strcmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
}
return (strcasecmp(substr($haystack, 0, strlen($needle)), $needle) === 0);
}
function endsWith($haystack, $needle, $case = true) {
if ($case) {
return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
}
return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)), $needle) === 0);
}
致谢:
这个问题已经有了很多答案,但在某些情况下,您可以选择比它们更简单的解决方案。如果您要查找的字符串是已知的(硬编码),则可以使用正则表达式,而不需要引用等。
检查字符串是否以'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()
)。
但是再次强调——这不是每种情况的解决方案,只适用于这个非常具体的情况。
上述正则表达式函数可以使用其他提议的调整进行更改:
function startsWith($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
# Checks if a string ends in a string
function endsWith($haystack, $needle) {
return substr($haystack,-strlen($needle))===$needle;
}
# This answer
function endsWith($haystack, $needle) {
return substr($haystack,-strlen($needle))===$needle;
}
# Accepted answer
function endsWith2($haystack, $needle) {
$length = strlen($needle);
return $length === 0 ||
(substr($haystack, -$length) === $needle);
}
# Second most-voted answer
function endsWith3($haystack, $needle) {
// search forward starting from end minus needle length characters
if ($needle === '') {
return true;
}
$diff = \strlen($haystack) - \strlen($needle);
return $diff >= 0 && strpos($haystack, $needle, $diff) !== false;
}
# Regex answer
function endsWith4($haystack, $needle) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
function timedebug() {
$test = 10000000;
$time1 = microtime(true);
for ($i=0; $i < $test; $i++) {
$tmp = endsWith('TestShortcode', 'Shortcode');
}
$time2 = microtime(true);
$result1 = $time2 - $time1;
for ($i=0; $i < $test; $i++) {
$tmp = endsWith2('TestShortcode', 'Shortcode');
}
$time3 = microtime(true);
$result2 = $time3 - $time2;
for ($i=0; $i < $test; $i++) {
$tmp = endsWith3('TestShortcode', 'Shortcode');
}
$time4 = microtime(true);
$result3 = $time4 - $time3;
for ($i=0; $i < $test; $i++) {
$tmp = endsWith4('TestShortcode', 'Shortcode');
}
$time5 = microtime(true);
$result4 = $time5 - $time4;
echo $test.'x endsWith: '.$result1.' seconds # This answer<br>';
echo $test.'x endsWith2: '.$result4.' seconds # Accepted answer<br>';
echo $test.'x endsWith3: '.$result2.' seconds # Second most voted answer<br>';
echo $test.'x endsWith4: '.$result3.' seconds # Regex answer<br>';
exit;
}
timedebug();
10000000x endsWith: 1.5760900974274 seconds # This answer
10000000x endsWith2: 3.7102129459381 seconds # Accepted answer
10000000x endsWith3: 1.8731069564819 seconds # Second most voted answer
10000000x endsWith4: 2.1521229743958 seconds # Regex answer
如果速度对你很重要,尝试这个方法。(我相信这是最快的方法)
仅适用于字符串,如果$haystack只有1个字符。
function startsWithChar($needle, $haystack)
{
return ($needle === $haystack[0]);
}
function endsWithChar($needle, $haystack)
{
return ($needle === $haystack[strlen($haystack) - 1]);
}
$str='|apples}';
echo startsWithChar('|',$str); //Returns true
echo endsWithChar('}',$str); //Returns true
echo startsWithChar('=',$str); //Returns false
echo endsWithChar('#',$str); //Returns false
endsWithChar('','x')
,但结果是正确的。 - Tino
s($str)->startsWith('|')
和s($str)->endsWith('}')
很有用,这些函数可以在这个独立的库中找到。 - cawstr_starts_with
和str_ends_with
。原文链接:https://stackoverflow.com/a/64160081/7082164 - Jsowa