PHP中的startsWith()和endsWith()函数
Posted
技术标签:
【中文标题】PHP中的startsWith()和endsWith()函数【英文标题】:startsWith() and endsWith() functions in PHP 【发布时间】:2010-10-24 11:22:33 【问题描述】:我如何编写两个函数来接收一个字符串,如果它以指定的字符/字符串开头或以它结尾,则返回?
例如:
$str = '|apples';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, ''); //Returns true
【问题讨论】:
查看 Laravel 的 Str class startsWith() 和 endsWith() 以了解 well-tested 方法。遇到过Edge cases,所以广泛使用这段代码是一个优势。 您可能会发现s($str)->startsWith('|')
和s($str)->endsWith('')
很有帮助,如this standalone library 中所示。
警告:这里的大多数答案在 UTF-8 等多字节编码中都是不可靠的。
根据我上面的评论,您可以确保使用最新版本(截至今天,5.4)。值得注意的是,startsWith() 已针对大型 haystack 字符串进行了优化。
php 8.0 为这项工作引入了新方法 str_starts_with
和 str_end_with
: ***.com/a/64160081/7082164
【参考方案1】:
PHP 8.0 及更高版本
从 PHP 8.0 开始,您可以使用
str_starts_with
Manual
和
str_ends_with
Manual
示例
echo str_starts_with($str, '|');
8.0 之前的 PHP
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;
【讨论】:
我会说 endsWith('foo', '') == false 是正确的行为。因为 foo 不会以任何形式结束。 'Foo' 以 'o'、'oo' 和 'Foo' 结尾。 EndsWith 可以写得更短:return substr($haystack, -strlen($needle))===$needle;
@RokKralj 但前提是$needle
不为空。
您可以通过将$length
作为第三个参数传递给substr
来完全避免if
:return (substr($haystack, -$length, $length);
。这通过返回一个空字符串而不是整个 $haystack
来处理 $length == 0
的情况。
@MrHus 我建议使用多字节安全函数,例如mb_strlen 和 mb_substr【参考方案2】:
PHP 8.0
从 PHP 8.0 开始,实现了两种新方法:
str_starts_with(string $haystack, string $needle): bool
Documentationstr_starts_with()
str_ends_with(string $haystack, string $needle): bool
Documentationstr_ends_with()
但它们区分大小写。函数返回 true 或 false。
$str = 'apples';
var_dump(str_starts_with($str, 'a')); // bool(true)
var_dump(str_starts_with($str, 'A')); // bool(false)
var_dump(str_ends_with($str, 's')); // bool(true)
var_dump(str_ends_with($str, 'S')); // bool(false)
【讨论】:
【参考方案3】:自 2021 年起更新,PHP > 8.0
PHP 8.0
引入了str_starts_with
和str_ends_with
。
str_starts_with( string $haystack , string $needle ) : bool
来源@https://www.php.net/manual/en/function.str-starts-with.php
str_ends_with( string $haystack , string $needle ) : bool
来源@https://www.php.net/manual/en/function.str-ends-with.php
用你的例子,我们会有:
$str = '|apples';
echo str_starts_with( $str, '|' ); //... true || 1
echo str_ends_with( $str, '' ); //... true || 1
【讨论】:
【参考方案4】: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 for this feature 提供了更多信息,还讨论了明显(和不那么明显)用户空间实现的优点和问题。
【讨论】:
【参考方案5】:做得更快:
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 return 立即,因此进行了许多比较 快得多(我测量时快了 7 倍)。在真正的情况下,您几乎不会为那条线路付出任何性能代价,所以我认为它值得包括在内。 (此外,在实践中,当您针对特定起始块测试多个字符串时,大多数比较都会失败,因为在典型情况下您正在寻找某些东西。)
注意:@Tino 下面评论中的错误已经修复
字符串与整数
如果您想强制进行字符串比较(即,您希望startsWith("1234",12) 为真),您需要进行一些类型转换:
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 开头吗?”之类的问题。 - 所以你决定,但要确保你决定好。
【讨论】:
代码中的错误:startsWith("123", "0")
给出true
是的,糟糕!$检查发生了。对不起! (只是想说明第 3 行中的概念)
@Tino 我想说我们现在可以删除这 2 个 cmets,您同意吗?我的意思是,点,它是固定的,它已经 2 年了。【参考方案6】:
对于 PHP 8 或更新版本,使用 str_starts_with
函数:
str_starts_with('http://www.google.com', 'http')
【讨论】:
【参考方案7】:Fastest endsWith() 解决方案:
# 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
【讨论】:
+1 花时间比较不同的解决方案并实际对它们进行基准测试!您还应该提及您使用的 PHP 版本,因为优化是随着语言的发展而完成的!从一个 PHP 版本到另一个 PHP 版本,我已经看到字符串比较函数的显着改进 :) 回应@ChristopheDeliens 和他提供 PHP 版本的请求。我在 7.3.2 上运行了您的测试,并在 FWIW 上得到了类似的结果。【参考方案8】:如果速度对你很重要,试试这个。(我相信这是最快的方法)
仅适用于字符串且 $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')
,但结果是正确的
我喜欢你的回答,但这很有趣,......针和干草堆是相反的:)......即你会在干草堆中搜索针,因此,它应该是:返回($needle === $haystack[0]); ,但很好的答案,谢谢!
@HeiderSati:很棒的观察!这就是@Tino 所说的Creative. Needles which contain haystacks.
...我没有给予足够的关注。谢谢!我修好了它。 :)【参考方案9】:
无复制和无实习生循环:
function startsWith(string $string, string $start): bool
return strrpos($string, $start, - strlen($string)) !== false;
function endsWith(string $string, string $end): bool
return ($offset = strlen($string) - strlen($end)) >= 0
&& strpos($string, $end, $offset) !== false;
【讨论】:
这应该比 MrHus 的实现要快得多!我可能会对其进行基准测试【参考方案10】:您可以为此使用fnmatch 函数。
// Starts with.
fnmatch('prefix*', $haystack);
// Ends with.
fnmatch('*suffix', $haystack);
【讨论】:
警告,不是二进制安全的,甚至对包含通配符的针头也不安全=/【参考方案11】:您可以使用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 (benchmark script) 上最快的解决方案之一。针对 8KB 干草堆、各种长度的针以及完整、部分和无匹配情况进行了测试。 strncmp
的启动速度更快,但无法检查结束。
【讨论】:
这个答案登上了 Daily WTF! :D 见thedailywtf.com/articles/… 请注意,@DavidWallace 和 @FrancescoMM cmets 适用于此答案的旧版本。当前答案使用strrpos
,如果 needle 与 haystack 的开头不匹配,则(应该)立即失败。
我不明白。基于php.net/manual/en/function.strrpos.php:“如果值为负,则搜索将从字符串末尾的那么多字符开始,向后搜索。”这似乎表明我们从字符 0 开始(由于 -strlength($haystack)
)并从那里搜索 backward?这不意味着你没有搜索任何东西吗?我也不明白其中的!== false
部分。我猜这是依赖于 PHP 的一个怪癖,其中一些值是“真实的”而另一些是“虚假的”,但在这种情况下它是如何工作的?
@Welbog:例如 haystack = xxxyyy
needle = yyy
并使用 strrpos
搜索从第一个 x
开始。现在我们在这里没有成功匹配(找到 x 而不是 y)并且我们不能再向后退(我们在字符串的开头)搜索失败立即。关于在上面的例子中使用!== false
-- strrpos
将返回 0 或 false 而不是其他值。同样,上例中的strpos
可以返回$temp
(预期位置)或false。为了保持一致性,我选择了!== false
,但您可以分别在函数中使用=== 0
和=== $temp
。
@spoo 已经确定 strpos === 0 是一个糟糕的解决方案,如果 haystack 很大并且不存在针头。【参考方案12】:
这是已接受答案的多字节安全版本,它适用于 UTF-8 字符串:
function startsWith($haystack, $needle)
$length = mb_strlen($needle, 'UTF-8');
return (mb_substr($haystack, 0, $length, 'UTF-8') === $needle);
function endsWith($haystack, $needle)
$length = mb_strlen($needle, 'UTF-8');
return $length === 0 ||
(mb_substr($haystack, -$length, $length, 'UTF-8') === $needle);
【讨论】:
我很确定这只是对 CPU 的浪费。对于 StarstWith 和 EndsWith,您需要检查的只是检查字节是否匹配,而这正是公认的答案正在做的事情。这 1 浪费时间计算针的 utf8 字符数,以及大海捞针的第 n 个 utf8 字符的位置。我认为,没有 100% 确定,这只是浪费 cpu。你能想出一个实际的测试用例,其中接受的答案失败了,而这没有? @hanshenrik - 顺便说一句,在极少数情况下,当您查找包含与 UTF8 相同字节但缺少最后一个字符的一半的字符串时。就像,你有 unicode C5 91(字母“ő”)并且你寻找 C5(字母“Å”)它不应该给你一个匹配。另一方面,当然,您为什么要在 utf 大海捞针中搜索非 utf 针...但是对于防弹检查,必须考虑这种可能性。 在startsWith
中应该是$length = mb_strlen($needle, 'UTF-8');
@ThomasKekeisen 谢谢,已修复。
被接受的(嗯,目前被接受的)解决方案已经是多字节安全的。它实际上是二进制安全的,这是一个更强大的保证。【参考方案13】:
这个问题已经有了很多答案,但在某些情况下,您可以选择比所有答案都简单的答案。 如果您要查找的字符串是已知的(硬编码),则可以使用正则表达式而无需任何引用等。
检查字符串是否以'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()
)。
但同样——这不是适用于所有情况的解决方案,只是这个非常具体的解决方案。
【讨论】:
您不需要对字符串进行硬编码。正则表达式可以是动态的。 @self true,但如果字符串不是硬编码的,则必须对其进行转义。目前这个问题有2个答案可以做到。这很容易,但它使代码稍微复杂了一点。所以我的观点是,对于可以进行硬编码的非常简单的情况,您可以保持简单。【参考方案14】:$ends_with = strrchr($text, '.'); // Ends with dot
$start_with = (0 === strpos($text, '.')); // Starts with dot
【讨论】:
根据文档, strrchr() 将返回最后一次出现 '.' 的字符串直到最后,这意味着您的 $ends_with 将是 true 如果 '.'是 $text 中的任何地方。因此 ends_with 应该是:('.' === strrchr($text, '.')) 由于您的答案是错误的并且没有按照它声称的那样做,并且您拒绝接受我的编辑以修复您的答案,因此我不赞成这个答案,因为它“非常不正确”。【参考方案15】: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";
结果 (PHP 7.0.9)
(从快到慢排序)
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
结果 (PHP 5.3.29)
(从快到慢排序)
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
startswith_benchmark.php
【讨论】:
如果字符串不是空的,就像在你的测试中一样,这实际上是更快(20-30%):function startswith5b($haystack, $needle) return ($haystack0==$needle0)?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
我在下面添加了一个回复。
@Jronny 因为 110 小于 133...??
该死,我不知道当时我脑子里是怎么想的。 Prolly 睡眠不足。
@mpen,我根本没有注意到大象:(
$haystack[0]
如果你不使用 isset 测试它会抛出一个通知错误。针也是一样。但是如果你添加测试,它会降低它的性能【参考方案16】:
不知道为什么这对人们来说如此困难。 Substr 做得很好而且效率很高,因为如果它不匹配,您不需要搜索整个字符串。
此外,由于我不是检查整数值而是比较字符串,所以我不必担心严格的 === 情况。但是,=== 是一个好习惯。
function startsWith($haystack,$needle)
substring($haystack,0,strlen($needle)) == $needle) return true;
return false;
function endsWith($haystack,$needle)
if(substring($haystack,-strlen($needle)) == $needle) return true;
return false;
甚至更好的优化。
function startsWith($haystack,$needle)
return substring($haystack,0,strlen($needle)) == $needle);
function endsWith($haystack,$needle)
return substring($haystack,-strlen($needle)) == $needle);
【讨论】:
与 MrHus 的回答相比,您的回答有什么不同或新的地方?【参考方案17】:mpen 的 answer 非常彻底,但不幸的是,所提供的基准有一个非常重要且有害的疏忽。
因为 needles 和 haystacks 中的每个字节都是完全随机的,所以 needle-haystack 对在第一个字节上不同的概率是 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
当然,这个基准可能仍然不是完全无偏的,但它也测试了在给定部分匹配针时算法的效率。
【讨论】:
【参考方案18】:您可以使用strpos
和strrpos
$bStartsWith = strpos($sHaystack, $sNeedle) == 0;
$bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle);
【讨论】:
你应该在这里使用三等号strpos($sHaystack, $sNeedle) == 0
像这样strpos($sHaystack, $sNeedle) === 0
吗?当false == 0
评估为true
时,我看到了一个错误。【参考方案19】:
到目前为止,所有答案似乎都做了很多不必要的工作,strlen calculations
、string allocations (substr)
等。'strpos'
和'stripos'
函数返回$needle
在$haystack
中第一次出现的索引:
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);
strlen() 并不是不必要的。如果字符串不是以给定的针开头,那么您的代码将不必要地扫描整个干草堆。
@mark 我用 1000 char haystack 和 10 或 800 char needle 做了一些基准测试,strpos 的速度提高了 30%。在说明某事是否更快之前先做你的基准测试......
如果有任何机会它还不是字符串(例如,如果它来自json_decode()
),您应该强烈考虑引用strpos($haystack, "$needle", 0)
之类的指针。否则,strpos()
的 [odd] 默认行为可能会导致意外结果:“If needle is not a string, it is converted to an integer and applied as the ordinal value of a character.”【参考方案20】:
这是 PHP 4 的有效解决方案。如果在 PHP 5 上使用 substr_compare
而不是 strcasecmp(substr(...))
,您可以获得更快的结果。
function stringBeginsWith($haystack, $beginning, $caseInsensitivity = false)
if ($caseInsensitivity)
return strncasecmp($haystack, $beginning, strlen($beginning)) === 0;
else
return strncmp($haystack, $beginning, strlen($beginning)) === 0;
function stringEndsWith($haystack, $ending, $caseInsensitivity = false)
if ($caseInsensitivity)
return strcasecmp(substr($haystack, strlen($haystack) - strlen($ending)), $haystack) === 0;
else
return strpos($haystack, $ending, strlen($haystack) - strlen($ending)) !== false;
【讨论】:
【参考方案21】:这些天我通常最终会使用像 underscore-php 这样的库。
require_once("vendor/autoload.php"); //use if needed
use Underscore\Types\String;
$str = "there is a string";
echo( String::startsWith($str, 'the') ); // 1
echo( String::endsWith($str, 'ring')); // 1
这个库还有很多其他方便的功能。
【讨论】:
【参考方案22】:之前的许多答案也同样有效。但是,这可能会尽可能短,并让它做你想做的事。您只需声明您希望它“返回真实”。所以我已经包含了返回布尔真/假和文本真/假的解决方案。
// boolean true/false
function startsWith($haystack, $needle)
return strpos($haystack, $needle) === 0 ? 1 : 0;
function endsWith($haystack, $needle)
return stripos($haystack, $needle) === 0 ? 1 : 0;
// textual true/false
function startsWith($haystack, $needle)
return strpos($haystack, $needle) === 0 ? 'true' : 'false';
function endsWith($haystack, $needle)
return stripos($haystack, $needle) === 0 ? 'true' : 'false';
【讨论】:
是的。然而,Peter 要求一个可以处理字符串的函数。尽管如此,我还是更新了我的答案来安抚你。 编辑后,您的解决方案现在完全过时了。它返回'true'
和 'false'
作为字符串,它们都是布尔意义上的 true
。不过对于underhanded.xcott.com 之类的东西来说,这是一个很好的模式;)
好吧,彼得刚刚说他希望它返回“真实”。所以我想我会退回他要求的东西。我已经添加了两个版本,以防万一这不是他想要的。【参考方案23】:
我会这样做
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;
【讨论】:
如果不匹配则忘记返回 false。 Errgo 不正确,因为函数的返回值不应该被“假设”,但至少与其他答案相比,我知道你在追求什么。【参考方案24】:为什么不如下?
//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(也称为开头)处找到针时才会返回 0。
这里是endsWith:
$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() as
(strpos($stringToSearch, $doesItStartWithThis) === 0)
将准确地返回真或假。
所有狂野的功能在这里猖獗地运行如此简单,这似乎很奇怪。
【讨论】:
如果你在字符串“abcdefghijklmxyz”中搜索“xy”而不是仅仅比较“x”和“a”并返回FALSE,你会查看从“a”到“m”的每个字符,这似乎很奇怪" 然后最终在字符串中找到 "xy",最后你返回 FALSE,因为它的位置不为零!这就是你正在做的事情,它比这里任何其他猖獗的功能都奇怪和狂野。 简单在于打字,而不是逻辑。 这不是逻辑,而是 Francsco 指出的可能的优化。使用strpos()
会很慢,除非它匹配。 strncmp()
在这种情况下会好很多。
当您执行此类低级功能时,您通常希望选择速度最优化的解决方案,无论多么复杂,因为这将被调用数百万次。您在这里获得或失去的每一微秒都会产生非常真实的影响。所以最好把它改掉(然后忘记复杂性,既然你有这个功能),而不是追求外观,然后在你甚至不知道出了什么问题的时候浪费了可怕的时间。想象一下检查一个不匹配的 2GB 字符串。【参考方案25】:
这里有两个不引入临时字符串的函数,这在针很大时可能很有用:
function startsWith($haystack, $needle)
return strncmp($haystack, $needle, strlen($needle)) === 0;
function endsWith($haystack, $needle)
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
【讨论】:
+1 从 PHP5.1 和 IMHO 最佳答案开始工作。但是endsWidth
应该做return $needle==='' || substr_compare(
... 所以它对-strlen($needle)===0
可以正常工作,如果没有修复,endsWith('a','')
返回false
@Tino 谢谢...我觉得这实际上是substr_compare()
中的一个错误,所以我添加了一个PR 来修复它:)
调用endsWith('', 'foo')
触发警告:“substr_compare(): 起始位置不能超过初始字符串长度”。也许这是substr_compare()
中的另一个错误,但为了避免它,您需要像...|| (strlen($needle) <= strlen($haystack) && substr_compare(
...) === 0);
之类的预检查
@gx_ 无需因为更多代码而放慢速度。只需使用return $needle === '' || @substr_compare(
.. 即可取消此警告。【参考方案26】:
我希望下面的答案既高效又简单:
$content = "The main string to search";
$search = "T";
//For compare the begining string with case insensitive.
if(stripos($content, $search) === 0) echo 'Yes';
else echo 'No';
//For compare the begining string with case sensitive.
if(strpos($content, $search) === 0) echo 'Yes';
else echo 'No';
//For compare the ending string with case insensitive.
if(stripos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';
//For compare the ending string with case sensitive.
if(strpos(strrev($content), strrev($search)) === 0) echo 'Yes';
else echo 'No';
【讨论】:
【参考方案27】: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);
贷方:
Check if a string ends with another string
Check if a string begins with another string
【讨论】:
strtolower 不是制作不区分大小写函数的最佳方式。在某些地区,大小写比上下更复杂。 我看到了抱怨,但没有解决方案......如果你要说这很糟糕,那么你也应该举一个例子来说明它应该是怎样的。 @WebDevHobo:这就是为什么我在您发表评论的前一天自己添加了一个答案。对于您的代码 strcasecmp 确实是正确的做法。【参考方案28】:关注startswith,如果你确定字符串不为空,在第一个字符上添加一个测试,在比较之前,strlen等,加快速度:
function startswith5b($haystack, $needle)
return ($haystack0==$needle0)?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;
不知何故(20%-30%)更快。添加另一个字符测试,例如 $haystack1===$needle1 似乎并没有加快速度,甚至可能减慢速度。
===
似乎比 ==
快
条件运算符(a)?b:c
似乎比if(a) b; else 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 不迭代整个字符串(但即使在那种情况下)这根本不方便。
【讨论】:
只有第一个字符不同时才会加快速度。 @Jack 是的,当然,这个想法是统计上发生的,所以整个测试集的加速通常是 20%-30%(包括没有不同的情况)。当它们不同时,您会获得很多,而当它们不同时,您会获得很少。平均而言,您会获得 30% 的收益(取决于设置,但大多数情况下您会在大型测试中获得速度) “但它不是这项工作的正确工具”...任何引用? WTF。我在下面列出了我应该引用谁的所有过程,除此之外?您会使用搜索到字符串末尾的函数来告诉您第一个字符不是“a”吗?谁在乎呢?这不是正确的工具,因为它是用于搜索的工具,而不是用于比较的工具,没有必要引用亚里士多德来陈述显而易见的事情!【参考方案29】:这可能有效
function startsWith($haystack, $needle)
return substr($haystack, 0, strlen($needle)) == $needle;
来源:https://***.com/a/4419658
【讨论】:
【参考方案30】:上面的正则表达式函数,但上面还建议了其他调整:
function startsWith($needle, $haystack)
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
function endsWith($needle, $haystack)
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
【讨论】:
在 php 中字符串操作的参数顺序是 $haystack, $needle。这些函数是倒数的,就像数组函数一样,排序实际上是 $needle, $haystack。以上是关于PHP中的startsWith()和endsWith()函数的主要内容,如果未能解决你的问题,请参考以下文章
PHP中的startsWith()和endsWith()函数
javascript中String.startswith和String.endsWidth 与 es6中的 startswith 和 endsWidth