字符串修剪的两种常见正则表达式方法之间的Perl性能是什么?

时间:2011-10-26 20:08:54

标签: regex perl

所以我正在研究一个执行大量处理的Perl脚本(没有太复杂,但很多),并决定做一些基准来比较两种常见的修剪方法字符串。

第一种方法是快速单行:

$word =~ s/^\s+|\s+$//g;

第二种方法有点长,但做同样的事情:

$word =~ s/^\s+//;
$word =~ s/\s+$//;

对于我的基准测试,我从一个包含4000万行的文件中读取脚本,每个行都进行修剪(除此之外什么也没做)。平均线长度小于20个字节。

第一种方法平均需要87秒才能完成 第二种方法平均需要27秒才能完成 不进行处理(只读线,继续)平均需要16秒。

第一个方法(第一遍)将匹配所有前导或尾随空格,然后将其删除,然后匹配并删除另一侧的前导/尾随空格。
第二种方法匹配并删除所有前导空格,然后匹配并删除所有尾随空格。

也许我在这里错了,但为什么第二种方法比第一种方法快3倍?

3 个答案:

答案 0 :(得分:11)

正则表达式引擎必须在第一种情况下做更多工作,即回溯以评估替代方案。您可以看到所涉及代码的不同之处:

echo " hello " |perl -Mre=debug -ple 's/^\s+|\s+$//g'
echo " hello " |perl -Mre=debug -ple 's/^\s+//;s/\s+$//'

答案 1 :(得分:5)

有意义的是,锚定的非回溯模式可以更好地进行优化(实际上是从已知字符位置开始的单个前向/后向顺序扫描);

有可能'选项'(|)使优化器退避,你得到标准的回溯,非常糟糕,因为许多空格可能不会尾随

答案 2 :(得分:2)

我怀疑Perl正则表达式可以通过使用模式的静态分析来优化第二个版本。例如,它可能会看到/^foo/必须在字符串的开头匹配。如果匹配失败,那么迭代字符串中的其余字符检查匹配是没有意义的。

  

默认情况下,“^”字符保证仅匹配字符串的开头,“$”字符仅匹配结尾(或结尾处的换行符之前), Perl执行某些优化假设字符串只包含一行。

Source(强调我的。)

第一个版本是一个更复杂的表达,并不是那么容易优化。