使用 strpos 检查字符串中是否存在
Checking for existence in a string with strpos
我只见过开发人员在使用 strpos
检查子字符串是否存在时使用严格比较:
if (strpos($haystack,$needle) !== false) {
}
我今天想到 可以 使用 is_numeric
ins
if (is_numeric(strpos($haystack,$needle))) {
}
是否有理由使用一个而不是另一个(特别是在这个用例中)?
仔细想想,strpos
的目的是return子串的位置。只有不存在,才会return false。该位置是数字。因此,is_numeric
在语义上是相当合格的。
因为 strpos
return 是整数或布尔值 false 可以使用 is_numeric
.
问题是:
惯用和autodocumented/self-descriptive,使用is_numeric
或将return值与布尔值进行比较? IMO,与 boolean false 相比更直观:
$string = 'new object';
$found = strpos($string,'new');
echo (is_numeric($found)) ? 'found' : 'not found';
echo "\n";
# much better
echo ($found !== false) ? 'found' : 'not found';
echo "\n";
此外,strpos(...) !== false
被过度使用,因为它是 PHP 文档所建议的。就这样变成了约定俗成。
- 在此上下文中使用 strpos 是为了比 preg_match 更快,在其上使用 is_numeric 通过增加更多开销来抵消这种速度优势。
- 使用另一个函数只是将 false 与其他函数分开是没有意义的,最好只使用 !== false
没有理由有人会使用 is_numeric,但它会起作用,只是速度较慢。
关于 strpos 与 preg_match:
preg_match() vs strpos() for match finding? 和
which is the fast process strpos()/stripos() or preg_match() in php
你说得对,is_numeric
与 strpos
一起工作。但这会使代码变得棘手,从而降低代码的可读性。
请记住,虽然这对您来说似乎很明显,但您正在让另一个阅读您的代码的程序员思考很多事情:
- 大海捞针里有吗?
- 大海捞针在哪个位置?
- strpos returns是什么类型的值?
- 这种情况下strpos的返回值是不是数字?
而 PHP 本身可能是一门相当 棘手的语言 ,看看这个例子:
if (strpos("needle in a haystack","needle")!==false) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
if (is_numeric(strpos("needle in a haystack","needle"))) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
if (is_int(strpos("needle in a haystack","needle"))) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// This doesn't work since 0 == false is true
if (strpos("needle in a haystack","needle")!=false) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// But this works since "haystack" position is not 0
if (strpos("needle in a haystack","haystack")!=false) {
echo "Haystack found!<br>";
} else {
echo "nothing found<br>";
}
// This doesn't work also because "needle" is at 0, and 0 is not a truthy value
if (strpos("needle in a haystack","needle")) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// But this works again since "haystack" position is not 0, and any int that's not 0 is truthy
if (strpos("needle in a haystack","haystack")) {
echo "Haystack found!<br>";
} else {
echo "nothing found<br>";
}
恕我直言,最好的选择是使用 ===false
和 ==!false
比较,如 the php documentation for strpos:
中所述
Warning
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
PD: 有关 "truthy" 的更好定义,请查看 this post.
我创建了一个基准。案例 check by compare with false value
总是比 check by is_numeric
.
快
// Init a big string array
for($i = 0; $i < 10000; $i++){
$str[] = 'a'.rand().'b'.rand();
}
// Case comparing with false value
$time1 = microtime(true);
foreach($str as $st){
$res[] = strpos($st,rand(0, count(array('b', 'c')) - 1 )) !== false;
}
$time2 = microtime(true);
echo $time2-$time1.'<br/>';
// Case 'is_numeric'
$time3 = microtime(true);
foreach($str as $st){
$res[] = is_numeric(strpos($st,rand(0, count(array('b', 'c')) - 1 )));
}
$time4 = microtime(true);
echo $time4-$time3;
//Time 1:
//0.018877029418945
//0.020556926727295
//Time 2:
//0.016352891921997
//0.016934871673584
//Time 3:
//0.0121009349823
//0.01330304145813
//Time 4:
//0.017507076263428
//0.01904296875
我发现这个问题是在搜索几乎相同的问题,只是我的想法是使用 is_int( )
而不是 is_numeric( )
。我无法真正理解发布的基准,所以我自己做了。总之,is_numeric( )
比[=15=慢了一根头发],is_int( )
快了一根头发。就个人而言,我发现它比 !== false
更易读,所以我可能会改用它。
这是在 php v7.1.23
下完成的
结果:
0.7900s for '!== false' with hits
4.5137s for '!== false' with misses
0.9297s for 'is_numeric' with hits
4.7509s for 'is_numeric' with misses
0.6391s for 'is_int' with hits
4.4862s for 'is_int' with misses
来自代码:
$n_times = 10000000;
$haystack_hit = " Certificate Name: example.com";
$heystack_miss = "Found the following certs:";
$needle = "Certificate Name:";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if (strpos($haystack_hit,$needle) !== false)
{ }
}
$end = microtime(true) - $start;
echo "\n" . round($end,4) . "s for '!== false' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if (strpos($haystack_miss,$needle) !== false)
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for '!== false' with misses\n\n";
// -----
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_numeric(strpos($haystack_hit,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_numeric' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_numeric(strpos($haystack_miss,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_numeric' with misses\n\n";
// -----
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_int(strpos($haystack_hit,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_int' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_int(strpos($haystack_miss,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_int' with misses\n";
我只见过开发人员在使用 strpos
检查子字符串是否存在时使用严格比较:
if (strpos($haystack,$needle) !== false) {
}
我今天想到 可以 使用 is_numeric
ins
if (is_numeric(strpos($haystack,$needle))) {
}
是否有理由使用一个而不是另一个(特别是在这个用例中)?
仔细想想,strpos
的目的是return子串的位置。只有不存在,才会return false。该位置是数字。因此,is_numeric
在语义上是相当合格的。
因为 strpos
return 是整数或布尔值 false 可以使用 is_numeric
.
问题是:
惯用和autodocumented/self-descriptive,使用is_numeric
或将return值与布尔值进行比较? IMO,与 boolean false 相比更直观:
$string = 'new object';
$found = strpos($string,'new');
echo (is_numeric($found)) ? 'found' : 'not found';
echo "\n";
# much better
echo ($found !== false) ? 'found' : 'not found';
echo "\n";
此外,strpos(...) !== false
被过度使用,因为它是 PHP 文档所建议的。就这样变成了约定俗成。
- 在此上下文中使用 strpos 是为了比 preg_match 更快,在其上使用 is_numeric 通过增加更多开销来抵消这种速度优势。
- 使用另一个函数只是将 false 与其他函数分开是没有意义的,最好只使用 !== false
没有理由有人会使用 is_numeric,但它会起作用,只是速度较慢。
关于 strpos 与 preg_match: preg_match() vs strpos() for match finding? 和 which is the fast process strpos()/stripos() or preg_match() in php
你说得对,is_numeric
与 strpos
一起工作。但这会使代码变得棘手,从而降低代码的可读性。
请记住,虽然这对您来说似乎很明显,但您正在让另一个阅读您的代码的程序员思考很多事情:
- 大海捞针里有吗?
- 大海捞针在哪个位置?
- strpos returns是什么类型的值?
- 这种情况下strpos的返回值是不是数字?
而 PHP 本身可能是一门相当 棘手的语言 ,看看这个例子:
if (strpos("needle in a haystack","needle")!==false) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
if (is_numeric(strpos("needle in a haystack","needle"))) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
if (is_int(strpos("needle in a haystack","needle"))) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// This doesn't work since 0 == false is true
if (strpos("needle in a haystack","needle")!=false) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// But this works since "haystack" position is not 0
if (strpos("needle in a haystack","haystack")!=false) {
echo "Haystack found!<br>";
} else {
echo "nothing found<br>";
}
// This doesn't work also because "needle" is at 0, and 0 is not a truthy value
if (strpos("needle in a haystack","needle")) {
echo "Needle found!<br>";
} else {
echo "nothing found<br>";
}
// But this works again since "haystack" position is not 0, and any int that's not 0 is truthy
if (strpos("needle in a haystack","haystack")) {
echo "Haystack found!<br>";
} else {
echo "nothing found<br>";
}
恕我直言,最好的选择是使用 ===false
和 ==!false
比较,如 the php documentation for strpos:
Warning This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
PD: 有关 "truthy" 的更好定义,请查看 this post.
我创建了一个基准。案例 check by compare with false value
总是比 check by is_numeric
.
// Init a big string array
for($i = 0; $i < 10000; $i++){
$str[] = 'a'.rand().'b'.rand();
}
// Case comparing with false value
$time1 = microtime(true);
foreach($str as $st){
$res[] = strpos($st,rand(0, count(array('b', 'c')) - 1 )) !== false;
}
$time2 = microtime(true);
echo $time2-$time1.'<br/>';
// Case 'is_numeric'
$time3 = microtime(true);
foreach($str as $st){
$res[] = is_numeric(strpos($st,rand(0, count(array('b', 'c')) - 1 )));
}
$time4 = microtime(true);
echo $time4-$time3;
//Time 1:
//0.018877029418945
//0.020556926727295
//Time 2:
//0.016352891921997
//0.016934871673584
//Time 3:
//0.0121009349823
//0.01330304145813
//Time 4:
//0.017507076263428
//0.01904296875
我发现这个问题是在搜索几乎相同的问题,只是我的想法是使用 is_int( )
而不是 is_numeric( )
。我无法真正理解发布的基准,所以我自己做了。总之,is_numeric( )
比[=15=慢了一根头发],is_int( )
快了一根头发。就个人而言,我发现它比 !== false
更易读,所以我可能会改用它。
这是在 php v7.1.23
下完成的结果:
0.7900s for '!== false' with hits
4.5137s for '!== false' with misses
0.9297s for 'is_numeric' with hits
4.7509s for 'is_numeric' with misses
0.6391s for 'is_int' with hits
4.4862s for 'is_int' with misses
来自代码:
$n_times = 10000000;
$haystack_hit = " Certificate Name: example.com";
$heystack_miss = "Found the following certs:";
$needle = "Certificate Name:";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if (strpos($haystack_hit,$needle) !== false)
{ }
}
$end = microtime(true) - $start;
echo "\n" . round($end,4) . "s for '!== false' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if (strpos($haystack_miss,$needle) !== false)
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for '!== false' with misses\n\n";
// -----
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_numeric(strpos($haystack_hit,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_numeric' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_numeric(strpos($haystack_miss,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_numeric' with misses\n\n";
// -----
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_int(strpos($haystack_hit,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_int' with hits\n";
$start = microtime(true);
for($i = 0; $i < $n_times; $i++)
{
if ( is_int(strpos($haystack_miss,$needle)) )
{ }
}
$end = microtime(true) - $start;
echo round($end,4) . "s for 'is_int' with misses\n";