我该如何编写两个函数,这些函数将接受字符串并以指定的字符/字符串开头或以指定的字符串结尾?
例如:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
我该如何编写两个函数,这些函数将接受字符串并以指定的字符/字符串开头或以指定的字符串结尾?
例如:
$str = '|apples}';
echo startsWith($str, '|'); //Returns true
echo endsWith($str, '}'); //Returns true
Answers:
function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
如果您不想使用正则表达式,请使用此选项。
$length
在的最后一行也不需要endsWith()
。
return substr($haystack, -strlen($needle))===$needle;
if
通过将$length
第三个参数传递给substr
:来完全避免return (substr($haystack, -$length, $length);
。$length == 0
通过返回一个空字符串而不是整个字符串来处理这种情况$haystack
。
您可以使用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
对于“开始于”而言是一种更快的触摸,但无法检查“结束于”。
strrpos
如果针与干草堆的开头不匹配,当前答案将立即使用哪个(应该)失败。
-strlength($haystack)
),然后从那里开始向后搜索?这不是意味着您没有搜索任何内容吗?我也不了解其中的!== false
部分。我猜这是基于PHP的古怪之处,其中某些值“真实”而另一些“虚假”,但是在这种情况下如何工作?
xxxyyy
needle =,yyy
并且使用strrpos
搜索从第一个开始x
。现在我们在这里没有成功的匹配项(找到了x而不是y),并且我们不能再返回了(我们在字符串的开头),搜索立即失败。关于使用!== false
- strrpos
在上面的示例中将返回0或false,而不返回其他值。同样,strpos
在上面的示例中可以返回$temp
(期望的位置)或false。我!== false
为了保持一致性而去了,但是您可以分别在和函数中使用=== 0
和=== $temp
。
更新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
function startswith5b($haystack, $needle) {return ($haystack{0}==$needle{0})?strncmp($haystack, $needle, strlen($needle)) === 0:FALSE;}
我在下面添加了答复。
所有的答案似乎到目前为止做不必要的工作负载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);
strpos($haystack, "$needle", 0)
如果有任何的机会,它是不是已经是一个字符串(例如,如果它是来自哪里json_decode()
)。否则,[odd]的默认行为strpos()
可能会导致意外的结果:“ 如果needle不是字符串,则将其转换为整数并用作字符的序数值。 ”
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);
}
贷给:
上面的regex功能,但上面也建议进行其他调整:
function startsWith($needle, $haystack) {
return preg_match('/^' . preg_quote($needle, '/') . '/', $haystack);
}
function endsWith($needle, $haystack) {
return preg_match('/' . preg_quote($needle, '/') . '$/', $haystack);
}
这个问题已经有很多答案,但是在某些情况下,您可以解决比所有问题都简单的问题。如果您要查找的字符串是已知的(硬编码),则可以使用正则表达式而无需任何引号等。
检查字符串是否以“ 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()
如上所示的函数。
但是,再次强调,这并不是针对每种情况的解决方案,而只是针对非常具体的情况。
如果速度对您很重要,请尝试一下。(我相信这是最快的方法)
仅适用于字符串,并且$ 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
endsWithChar('','x')
,但结果是正确的
这是两个不引入临时字符串的函数,当针头很大时可能会有用:
function startsWith($haystack, $needle)
{
return strncmp($haystack, $needle, strlen($needle)) === 0;
}
function endsWith($haystack, $needle)
{
return $needle === '' || substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
endsWidth
应该做return $needle==='' || substr_compare(
...使其按预期工作-strlen($needle)===0
,如果没有修复,它会endsWith('a','')
返回false
endsWith('', 'foo')
触发警告:“ substr_compare():起始位置不能超过初始字符串长度”。也许这是中的另一个错误substr_compare()
,但是要避免出现此错误,您需要进行类似... || (strlen($needle) <= strlen($haystack) && substr_compare(
... 的预检查……) === 0);
return $needle === '' || @substr_compare(
..禁止显示此警告。
# 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
我知道已经完成了,但是您可能要看一下strncmp,因为它允许您输入要比较的字符串的长度,因此:
function startsWith($haystack, $needle, $case=true) {
if ($case)
return strncasecmp($haystack, $needle, strlen($needle)) == 0;
else
return strncmp($haystack, $needle, strlen($needle)) == 0;
}
这是已接受答案的多字节安全版本,适用于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);
}
startsWith
它应该是$length = mb_strlen($needle, 'UTF-8');
简短且易于理解的单行代码,不带正则表达式。
startsWith()很简单。
function startsWith($haystack, $needle) {
return (strpos($haystack, $needle) === 0);
}
EndsWith()使用稍微花哨且缓慢的strrev():
function endsWith($haystack, $needle) {
return (strpos(strrev($haystack), strrev($needle)) === 0);
}
专注于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
快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不会迭代整个字符串(但是即使在那种情况下),这也不方便。
我希望以下答案可能有效且简单:
$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';
将答案通过MPEN是非常彻底的,但不幸的是,所提供的基准具有非常重要的和有害的监督。
因为针和干草堆中的每个字节都是完全随机的,所以针-干草堆对在第一个字节上发生差异的概率为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
当然,该基准可能仍然不是完全无偏的,但是当给定部分匹配的针时,它也会测试算法的效率。
只是一个建议:
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)));
}
比较字符串的第一个字符的那一行额外内容可以立即使错误的大小写返回,因此使您的许多比较都快得多(我测量时,快7倍)。在真实情况下,您几乎不需要为这条单线的性能付出任何代价,因此我认为值得考虑。(此外,实际上,当您针对特定的起始块测试许多字符串时,大多数比较都会失败,因为在典型情况下,您正在寻找某些东西。)
startsWith("123", "0")
给出true
该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
}
测试(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/zh/function.substr-compare.php
这可能有效
function startsWith($haystack, $needle) {
return substr($haystack, 0, strlen($needle)) == $needle;
}
我会这样
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;
}
根据詹姆斯·布莱克(James Black)的回答,以下是endWith版本:
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);
}
注意:我已经将if-else部分替换为James Black的startsWith函数,因为strncasecmp实际上是strncmp的不区分大小写的版本。
strrev()
很有创意,但成本很高,尤其是当您说的是... 100Kb时。
===
而不是==
确定。0
等于PHP中的很多东西。
为什么不以下?
//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。
结束于:
$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()
(strpos($stringToSearch, $doesItStartWithThis) === 0)
将准确地返回true或false。
看起来如此简单,所有狂野功能在这里肆虐,这似乎很奇怪。
strpos()
除非匹配,否则使用会很慢。strncmp()
在这种情况下会更好。
先前的许多答案也将同样有效。但是,这可能会尽可能的短,让它按照自己的意愿进行。您只是说您希望它“返回真实”。因此,我包含了返回布尔值true / false和文本true / false的解决方案。
// 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';
}
您还可以使用正则表达式:
function endsWith($haystack, $needle, $case=true) {
return preg_match("/.*{$needle}$/" . (($case) ? "" : "i"), $haystack);
}
preg_quote($needle, '/')
。
无复制和无内部循环:
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;
}
这是针对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;
}
您可以为此使用fnmatch函数。
// Starts with.
fnmatch('prefix*', $haystack);
// Ends with.
fnmatch('*suffix', $haystack);