PHP中的startsWith()和endsWith()函数

我如何编写两个函数,如果以指定的字符/string开头或以它结束,则返回一个string并返回?

例如:

$str = '|apples}'; echo startsWith($str, '|'); //Returns true echo endsWith($str, '}'); //Returns true 
 function startsWith($haystack, $needle) { $length = strlen($needle); return (substr($haystack, 0, $length) === $needle); } function endsWith($haystack, $needle) { $length = strlen($needle); return $length === 0 || (substr($haystack, -$length) === $needle); } 

如果你不想使用正则expression式,使用这个。

可以使用strrposstrpos分别检查start-with和strrpos

请注意,使用strrpos来检查开始和strpos来检查结束将尽快返回而不是检查整个string,直到结束。 此外,此解决scheme不会创build一个临时string。 考虑解释之前的原因downvoting。 只是因为DWTF的f-wit不明白这个函数是如何工作的,或者认为只有一个解决scheme并不意味着这个答案是错误的。

 function startsWith($haystack, $needle) { // search backwards starting from haystack length characters from the end return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== false; } function endsWith($haystack, $needle) { // search forward starting from end minus needle length characters return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false); } 

testing和结果( 与此对比 ):

 startsWith("abcdef", "ab") -> true startsWith("abcdef", "cd") -> false startsWith("abcdef", "ef") -> false startsWith("abcdef", "") -> true startsWith("", "abcdef") -> false endsWith("abcdef", "ab") -> false endsWith("abcdef", "cd") -> false endsWith("abcdef", "ef") -> true endsWith("abcdef", "") -> true endsWith("", "abcdef") -> false 

注意: strncmpsubstr_compare函数将胜过这个函数。

2016年8月23日更新

function

 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; } 

testing

 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)

(sorting最快到最慢)

 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)

(sorting最快到最慢)

 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

到目前为止,所有的答案似乎都做了不必要的工作, strlen calculationsstring allocations (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; } 
 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); } 

积分

检查string是否以另一个string结尾

检查一个string是否以另一个string开头

上面的正则expression式函数,但也有上面build议的其他调整:

  function startsWith($needle, $haystack) { return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack); } function endsWith($needle, $haystack) { return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack); } 

我意识到这已经完成了,但你可能想看看strncmp,因为它允许你把string的长度进行比较,所以:

 function startsWith($haystack, $needle, $case=true) { if ($case) return strncasecmp($haystack, $needle, strlen($needle)) == 0; else return strncmp($haystack, $needle, strlen($needle)) == 0; } 

如果速度对你很重要,试试这个(我相信这是最快的方法)

仅适用于string,如果$ haystack只有1个字符

 function startsWithChar($needle, $haystack) { return ($needle[0] === $haystack); } function endsWithChar($needle, $haystack) { return ($needle[strlen($needle) - 1] === $haystack); } $str='|apples}'; echo startsWithChar($str,'|'); //Returns true echo endsWithChar($str,'}'); //Returns true echo startsWithChar($str,'='); //Returns false echo endsWithChar($str,'#'); //Returns false 

这里有两个函数不会引入一个临时string,当针头非常大时这可能是有用的:

 function startsWith($haystack, $needle) { return strncmp($haystack, $needle, strlen($needle)) === 0; } function endsWith($haystack, $needle) { return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0; } 

你可以使用strposstrrpos

 $bStartsWith = strpos($sHaystack, $sNeedle) == 0; $bEndsWith = strrpos($sHaystack, $sNeedle) == strlen($sHaystack)-strlen($sNeedle); 

这个问题已经有了很多答案,但在某些情况下,你可以解决比所有问题都简单的问题。 如果你正在寻找的string是已知的(硬编码),你可以使用正则expression式而不用任何引用等。

检查一个string是否以'ABC'开始:

 preg_match('/^ABC/', $myString); // "^" here means beginning of string 

以'ABC'结尾:

 preg_match('/ABC$/', $myString); // "$" here means end of string 

在我的简单情况下,我想检查一个string是否以斜线结尾:

 preg_match('/\/$/', $myPath); // slash has to be quoted 

优点:因为它非常简短,所以你不必像上面那样定义一个函数(比如endsWith() )。

但是,再次 – 这不是每个案件的解决scheme,只是这个非常具体的案例。

短而易懂的单行无正则expression式。

startsWith()是直截了当的。

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

endsWith()使用稍微花哨和缓慢的strrev():

 function endsWith($haystack, $needle) { return (strpos(strrev($haystack), strrev($needle)) === 0); } 

关注首先,如果你确定string不是空的,在比较之前,strlen等等加起来的第一个字符的testing,加快了一点:

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

不知何故(20%-30%)更快。 添加另一个字符testing,比如$ haystack {1} === $ needle {1}似乎不会加速太多,甚至可能会减慢速度。

===似乎比==有条件的运算符(a)?b:c似乎比if(a) b; else c;更快if(a) b; else c; if(a) b; else c;


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


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不会迭代整个string(但即使在这种情况下)也是不方便的。

我希望下面的答案可能有效,也很简单:

 $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'; 

这些日子我通常最终会像下划线一样使用库。

 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 

图书馆充满了其他方便的function。

在很多特殊情况下, substr函数可以返回false ,所以这里是我的版本,它处理这些问题:

 function startsWith( $haystack, $needle ){ return $needle === ''.substr( $haystack, 0, strlen( $needle )); // substr's false => empty string } function endsWith( $haystack, $needle ){ $len = strlen( $needle ); return $needle === ''.substr( $haystack, -$len, $len ); // ! len=0 } 

testing( true意味着好):

 var_dump( startsWith('','')); var_dump( startsWith('1','')); var_dump(!startsWith('','1')); var_dump( startsWith('1','1')); var_dump( startsWith('1234','12')); var_dump(!startsWith('1234','34')); var_dump(!startsWith('12','1234')); var_dump(!startsWith('34','1234')); var_dump('---'); var_dump( endsWith('','')); var_dump( endsWith('1','')); var_dump(!endsWith('','1')); var_dump( endsWith('1','1')); var_dump(!endsWith('1234','12')); var_dump( endsWith('1234','34')); var_dump(!endsWith('12','1234')); var_dump(!endsWith('34','1234')); 

另外, substr_compare函数也值得一看。 http://www.php.net/manual/en/function.substr-compare.php

简而言之:

 function startsWith($str, $needle){ return substr($str, 0, strlen($needle)) === $needle; } function endsWith($str, $needle){ $length = strlen($needle); return !$length || substr($str, - $length) === $needle; } 

这可能工作

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

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

为什么不是以下?

 //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开始时发现价值!

请记住,如果在干草堆中找不到针,则条件将返回错误,并且如果并且仅当在指数0(也就是开始处)处发现针,则返回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()as

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

会准确地返回真实或错误。

这似乎很奇怪,这里所有的野生function都很stream行。

我会这样做

  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; } 

这个答案令人难以置信,但不幸的是,所提供的基准有一个非常重要和有害的监督。

因为针和干草堆中的每个字节都是完全随机的,所以在第一个字节中针干草堆对的不同的概率是99.609375%,这意味着平均来说,100000对中的大约99609将在第一个字节。 换句话说,基准很大程度上偏向于明确地检查第一个字节的实现,就像strncmp_startswith2那样。

如果testing生成循环实现如下:

 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 />"; 

基准testing结果说明了一个稍微不同的故事

 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 

当然,这个基准可能仍然不是完全无偏见的,但是当给定部分匹配的针时,它testingalgorithm的效率。

基于詹姆斯·布莱克的回答,这里是它的结尾与版本:

 function startsWith($haystack, $needle, $case=true) { if ($case) return strncmp($haystack, $needle, strlen($needle)) == 0; else return strncasecmp($haystack, $needle, strlen($needle)) == 0; } function endsWith($haystack, $needle, $case=true) { return startsWith(strrev($haystack),strrev($needle),$case); } 

注意:我已经换了James Black的startsWith函数的if-else部分,因为strncasecmp实际上是strncmp的不区分大小写的版本。

只是一个build议:

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

多余的一行,比较string的第一个字符,可以使错误的情况立即返回,因此使许多比较更快(当我测量时快7倍)。 在这种情况下,你几乎不会为这条单线的性能付出代价,所以我认为这是值得的。 (另外,在实践中,当你为一个特定的起始块testing很多string时,大多数比较都会失败,因为在一个典型的情况下你正在寻找一些东西。)

 $ends_with = strrchr($text, '.'); // Ends with dot $start_with = (0 === strpos($text, '.')); // Starts with dot 

你也可以使用正则expression式:

 function endsWith($haystack, $needle, $case=true) { return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack); } 

许多以前的答案也可以。 然而,这可能就像你能做到的一样短,并且做到你想做的事情。 你只是说,你希望它“返回true”。 所以我已经包含了返回布尔值true / false和文本true / false的解决scheme。

 // 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'; } 

这是PHP 4的高效解决scheme。如果使用substr_compare而不是strcasecmp(substr(...))则PHP 5上的结果可能会更快。

 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; } 

这是一个接受的答案的多字节安全版本,它适用于UTF-8string:

 function startsWith($haystack, $needle) { $length = mb_substr($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); } 

不知道为什么这是如此困难的人。 Substr做得非常好,而且效率很高,因为如果不匹配,你不需要search整个string。

Additionally, since I'm not checking integer values but comparing strings I don't have to necessarily have to worry about the strict === case. However, === is a good habit to get into.

 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; } 

or even better optimized.

 function startsWith($haystack,$needle) { return substring($haystack,0,strlen($needle)) == $needle); } function endsWith($haystack,$needle) { return substring($haystack,-strlen($needle)) == $needle); }