gpt4 book ai didi

php - Preg_replace的效率

转载 作者:行者123 更新时间:2023-12-04 03:15:28 24 4
gpt4 key购买 nike

执行摘要:

preg_replace() 比字符串比较运行得更快。为什么?正则表达式不应该更慢吗?


recent question 中关于在给定输入中检测任何不允许的子字符串数组,我建议将 preg_replace() 调用的结果与原始输入进行比较,因为 preg_replace() 可以采用一组模式作为输入。因此,我的方法可以是单个 if,而其他解决方案需要一个(或多个)循环。

我对辩论我的答案不感兴趣,因为它实际上比循环更不易读/可维护。我的答案仍然是 -1,为了可读性/易于维护我会接受,但我的方法指出的最大错误是缺乏效率。这让我很好奇,并促使我进行了一些测试。我的结果有点出乎我的意料:在所有其他因素相同的情况下,preg_replace() 比任何其他方法都快

您能解释一下为什么会这样吗?

可以在下面找到这些测试的代码以及结果:

$input = "In a recent question about detecting any of an array of disallowed substrings within a given input, I suggested comparing the result of a `preg_replace()` call to the original input, since `preg_replace()` can take an array of patterns as input. Thus my method for this could be a single `if` whereas the other solutions required one (or many) loops. I'm not interested in debating my answer, because really it is less readable/maintainable than the loops. However, the biggest fault pointed out with my method was a lack of efficiency. That got me curious, and led me to do some testing. My results were a bit surprising to me: with all other factors held equal, `preg_replace()` was **faster** than any of the other methods. Can you explain why this was the case?";
$input2 = "Short sentence - no matches";
$input3 = "Word";
$input4 = "Short sentence - matches loop";

$start1 = microtime(true);
$rejectedStrs = array("loop", "efficiency", "explain");
$p_matches = 0;
for ($i = 0; $i < 10000; $i++) {
if (str_check($rejectedStrs, $input)) $p_matches++;
if (str_check($rejectedStrs, $input2)) $p_matches++;
if (str_check($rejectedStrs, $input3)) $p_matches++;
if (str_check($rejectedStrs, $input4)) $p_matches++;
}

$start2 = microtime(true);
$rejectedStrs = array("loop", "efficiency", "explain");
$l_matches = 0;
for ($i = 0; $i < 10000; $i++) {
if (loop_check($rejectedStrs, $input)) $l_matches++;
if (loop_check($rejectedStrs, $input2)) $l_matches++;
if (loop_check($rejectedStrs, $input3)) $l_matches++;
if (loop_check($rejectedStrs, $input4)) $l_matches++;
}

$start3 = microtime(true);
$rejectedStrs = array("/loop/", "/efficiency/", "/explain/");
$s_matches = 0;
for ($i = 0; $i < 10000; $i++) {
if (preg_check($rejectedStrs, $input)) $s_matches++;
if (preg_check($rejectedStrs, $input2)) $s_matches++;
if (preg_check($rejectedStrs, $input3)) $s_matches++;
if (preg_check($rejectedStrs, $input4)) $s_matches++;
}

$end = microtime(true);
echo $p_matches." ".$l_matches." ".$s_matches."\n";
echo "str_match: ".$start1." ".$start2."= ".($start2-$start1)."\nloop_match: ".$start2." ".$start3."=".($start3-$start2)."\npreg_match: ".$start3." ".$end."=".($end-$start3);

function preg_check($rejectedStrs, $input) {
if($input == preg_replace($rejectedStrs, "", $input))
return true;
return false;
}

function loop_check($badwords, $string) {

foreach (str_word_count($string, 1) as $word) {
foreach ($badwords as $bw) {
if (stripos($word, $bw) === 0) {
return false;
}
}
}
return true;
}

function str_check($badwords, $str) {
foreach ($badwords as $word) {
if (stripos(" $str ", " $word ") !== false) {
return false;
}
}
return true;
}

结果

20000 20000 20000

str_match: 1282270516.6934 1282270518.5881= 1.894730091095

loop_match: 1282270518.5881 1282270523.0943=4.5061857700348

preg_match: 1282270523.0943 1282270523.6191=0.52475500106812

最佳答案

我们先来看preg_checkloop_check。他们都必须遍历整个字符串,并且必须检查每次遍历中的每个单词。所以它们的行为至少是 O(n*m),其中 n 是字符串的长度,m 是坏词的数量.您可以通过增加 nm 的值运行算法并绘制 3D 图形来测试这一点(但是,您可能需要也可能不需要以非常高的速度运行它nm 的高值可以看到这种行为)。

loop_check 在这里更多(渐近地)高效。原因是字符串的单词数量与其长度不成正比——我记得它通常遵循对数函数。它可能使用哈希表来存储它通过这种方式找到的词,这是在平均恒定时间内完成的(如果我们忽略这一点,我们可能不得不不时地重建哈希表以容纳更多元素)。

因此 loop_check 将具有类似 n + m * log(n) 的渐近行为,这比 n*m.

现在,这是指算法的渐近行为,即,当 mn 变得非常大(可能需要“非常非常”)时。对于较小的 mn 值,常量起着重要作用。特别是,执行 PHP 操作码和 PHP 函数调用比用 C 语言实现的相同任务成本更高,只需一个函数调用。这不会使正则表达式算法更快,它只会使 mn 的小值更快。

关于php - Preg_replace的效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3527746/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com