在 preg_replace() 之前使用 strpos() 是否更快?

mgu*_*utt 1 php regex preg-replace strpos

假设我们preg_replace在数百万个帖子字符串上使用它:

function makeClickableLinks($s) {
    return preg_replace('@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@', '<a href="$1" target="_blank">$1</a>', $s);
}
Run Code Online (Sandbox Code Playgroud)

假设所有帖子中只有 10% 包含链接,strpos($string, 'http') !== false在调用之前检查会更快preg_replace()吗?如果是这样,为什么?不在preg_replace()内部执行一些预测试?

Dra*_*kes 5

令人惊讶的是,是的!

以下是您使用这两个函数分析 10,000,000 个字符串的基准:

测试 1 - 与模式匹配的字符串:

"Here is a great new site to visit at http://example.com so go there now!"
Run Code Online (Sandbox Code Playgroud)


在 preg_replace 花费 12.6124269962 秒之前,单独 preg_replace 花费了 10.9626309872 秒strpos ?慢点

测试 2 - 与模式不匹配的字符串:

"Here is a great new site to visit at ftp://example.com so go there now!"
Run Code Online (Sandbox Code Playgroud)


在 preg_replace 花费 2.91205692291 秒之前,单独 preg_replace 花费了 6.51636195183 秒strpos ?快点

测试 3 - 10% 的字符串与模式匹配:

"Here is a great new site to visit at ftp://example.com so go there now!" (90%)
"Here is a great new site to visit at http://example.com so go there now!" (10%)
Run Code Online (Sandbox Code Playgroud)


在 preg_replace 花费 4.31978201866 秒之前,单独 preg_replace 花费了 7.43295097351 秒strpos ?快点

这只是对两个字符串的简单基准测试,但速度有明显差异。


这是“10%”案例的测试工具:

<?php
$string1 = "Here is a great new site to visit at http://example.com so go there now!";
$string2 = "Here is a great new site to visit at ftp://example.com so go there now!";

function makeClickableLinks1($s) {
    return preg_replace('@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@', '<a href="$1" target="_blank">$1</a>', $s);
}

function makeClickableLinks2($s) {
    return strpos($s, 'http') !== false ? preg_replace('@(https?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@', '<a href="$1" target="_blank">$1</a>', $s) : null;
}

/* Begin test harness */

$loops = 10000000;

function microtime_float() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

/* Test using only preg_replace */

$time_start = microtime_float();
for($i = 0; $i < $loops; $i++) {
    // Only 10% of strings will have "http"
    makeClickableLinks1($i % 10 ? $string2 : $string1);
}
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "preg_replace alone took $time seconds<br/>";

/* Test using strpos before preg_replace */

$time_start = microtime_float();
for($i = 0; $i < $loops; $i++) {
    // Only 10% of strings will have "http"
    makeClickableLinks2($i % 10 ? $string2 : $string1);
}
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "strpos before preg_replace took $time seconds<br/>";
?>
Run Code Online (Sandbox Code Playgroud)