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式,使用这个。
可以使用strrpos
和strpos
分别检查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
注意: strncmp
和substr_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 calculations
, string 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; }
你可以使用strpos
和strrpos
$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); }