- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
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_check
和loop_check
。他们都必须遍历整个字符串,并且必须检查每次遍历中的每个单词。所以它们的行为至少是 O(n*m)
,其中 n
是字符串的长度,m
是坏词的数量.您可以通过增加 n
和 m
的值运行算法并绘制 3D 图形来测试这一点(但是,您可能需要也可能不需要以非常高的速度运行它n
和 m
的高值可以看到这种行为)。
loop_check
在这里更多(渐近地)高效。原因是字符串的单词数量与其长度不成正比——我记得它通常遵循对数函数。它可能使用哈希表来存储它通过这种方式找到的词,这是在平均恒定时间内完成的(如果我们忽略这一点,我们可能不得不不时地重建哈希表以容纳更多元素)。
因此 loop_check
将具有类似 n + m * log(n)
的渐近行为,这比 n*m
.
现在,这是指算法的渐近行为,即,当 m
和 n
变得非常大(可能需要“非常非常”)时。对于较小的 m
和 n
值,常量起着重要作用。特别是,执行 PHP 操作码和 PHP 函数调用比用 C 语言实现的相同任务成本更高,只需一个函数调用。这不会使正则表达式算法更快,它只会使 m
和 n
的小值更快。
关于php - Preg_replace的效率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3527746/
第一个 .on 函数比第二个更有效吗? $( "div.container" ).on( "click", "p", function(){ }); $( "body" ).on( "click",
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 已关闭 7 年前。 Improve
我有这样的查询: $('#tabContainer li'); JetBrains WebStorm IDE 将其突出显示为低效查询。它建议我改用这个: $('#tabContainer').find
我刚刚在 coursera ( https://www.coursera.org/saas/) 上听了一个讲座,教授说 Ruby 中的一切都是对象,每个方法调用都是在对象上调用发送方法,将一些参数传递
这可能是用户“不喜欢”的另一个问题,因为它更多的是与建议相关而不是与问题相关。 我有一个在保存和工作簿打开时触发的代码。 它在 f(白天与夜晚,日期与实际日期)中选择正确的工作表。 周一到周三我的情况
这只是我的好奇心,但是更有效的是递归还是循环? 给定两个功能(使用通用lisp): (defun factorial_recursion (x) (if (> x 0) (*
这可能是一个愚蠢的问题,但是while循环的效率与for循环的效率相比如何?我一直被教导,如果可以使用for循环,那我应该这样做。但是,实际上之间的区别是什么: $i = 0; while($i <
我有一个Elasticsearch索引,其中包含几百万条记录。 (基于时间戳的日志记录) 我需要首先显示最新记录(即,按时间戳降序排列的记录) 在时间戳上排序desc是否比使用时间戳的函数计分功能更有
使用Point2D而不是double x和y值时,效率有很大差异吗? 我正在开发一个程序,该程序有许多圆圈在屏幕上移动。他们各自从一个点出发,并越来越接近目的地(最后,他们停下来)。 使用 .getC
我正在编写一个游戏,并且有一个名为 GameObject 的抽象类和三个扩展它的类(Player、Wall 和 Enemy)。 我有一个定义为包含游戏中所有对象的列表。 List objects; 当
我是 Backbone 的初学者,想知道两者中哪一个更有效以及预期的做事方式。 A 型:创建一个新集合,接受先前操作的结果并从新集合中提取 key result = new Backbone.Coll
最近,关于使用 LIKE 和通配符搜索 MS SQL 数据库的最有效方法存在争论。我们正在使用 %abc%、%abc 和 abc% 进行比较。有人说过,术语末尾应该始终有通配符 (abc%)。因此,根
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 8 年前。 Improv
我想知道,这样做会更有效率吗: setVisible(false) // if the component is invisible 或者像这样: if(isVisible()){
我有一个静态方法可以打开到 SQL Server 的连接、写入日志消息并关闭连接。我在整个代码中多次调用此方法(平均每 2 秒一次)。 问题是 - 它有效率吗?我想也许积累一些日志并用一个连接插入它们
这个问题在这里已经有了答案: Best practice to avoid memory or performance issues related to binding a large numbe
我为我的 CS 课(高中四年级)制作了一个石头剪刀布游戏,我的老师给我的 shell 文件指出我必须将 do while 循环放入运行者中,但我不明白为什么?我的代码可以工作,但她说最好把它写在运行者
我正在编写一个需要通用列表的 Java 应用程序。该列表需要能够经常动态地调整大小,对此的明显答案是通用的Linkedlist。不幸的是,它还需要像通过调用索引添加/删除值一样频繁地获取/设置值。 A
我的 Mysql 语句遇到了真正的问题,我需要将几个表连接在一起,查询它们并按另一个表中值的平均值进行排序。这就是我所拥有的... SELECT ROUND(avg(re.rating
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: Is there a difference between i==0 and 0==i? 以下编码风格有什么
我是一名优秀的程序员,十分优秀!