在Perl中,以下哪种正则表达式构造最快?
/foo(?>.*?bar)/s
/foo(?:(?!bar).)*+bar/s
/foo(?:[^b]++|b(?!ar))*+bar/
对于foo
和bar
之间距离较大的大字符串(内容为b
)。 (PCRE答案也很有趣。)
答案 0 :(得分:5)
use Benchmark;
找出准确的测量值。
答案 1 :(得分:0)
由于这很容易测试,我认为你要么作为脑筋急转弯,要么作为检查自己假设的一种方式;我会咬人的。 ;)
我希望#3最快。 .*?bar
实际上与(?:(?!bar).)*
相同,因此#1和#2都必须在每个位置进行预测。 #3只有在看到b
时才会执行一次。
答案 2 :(得分:0)
ab(?>.*?cd)
ab(?:(?!cd).)*+cd
ab(?:[^c]++|c(?!d))*+cd
在上面问题的简单情况下,使用长测试字符串,以及Perl 5.12上的以下代码,答案是第一个正则表达式胜过其他,第二个是最慢的(如可疑的)。
这些是每秒迭代次数的结果(缩放到最慢的一次):
使用代码:
use v5.12;
use Benchmark qw(:hireswallclock :all);
my $str = '';
my $ab = 'ab' x 1024**2;
$str .= $ab . 'cd';
$str .= $ab . 'cde';
$str .= $ab . 'cdef';
$str .= $ab . 'cdefg';
$str .= $ab . 'cdefgh';
printf "Test string length: %.2f MiB\n", (length($str)/1024**2);
timethese(-10, {
'0:index' => sub { index($str, 'cdefgh') },
'1:match' => sub { $str =~ /ab(?>.*?cdefgh)/ },
'1:fail' => sub { $str =~ /ab(?>.*?cdefgg)/ },
'2:match' => sub { $str =~ /ab(?:(?!cdefgh).)*+cdefgh/ },
'2:fail' => sub { $str =~ /ab(?:(?!cdefgg).)*+cdefgg/ },
'3:match' => sub { $str =~ /ab(?:[^c]++|c(?!defgh))*+cdefgh/ },
'3:fail' => sub { $str =~ /ab(?:[^c]++|c(?!defgg))*+cdefgg/ },
});
输出:
Test string length: 10.00 MiB
Benchmark: running 0:index, 1:fail, 1:match, 2:fail, 2:match, 3:fail, 3:match for at least 10 CPU seconds...
0:index: 11.0578 wallclock secs (10.00 usr + 0.00 sys = 10.00 CPU) @ 246.70/s (n=2467)
1:fail: 11.0379 wallclock secs (10.05 usr + 0.00 sys = 10.05 CPU) @ 245.05/s (n=2462)
1:match: 11.9981 wallclock secs (10.08 usr + 0.00 sys = 10.08 CPU) @ 63.80/s (n=643)
2:fail: 12.0531 wallclock secs (10.53 usr + 0.00 sys = 10.53 CPU) @ 255.25/s (n=2688)
2:match: 11.0573 wallclock secs (10.13 usr + 0.00 sys = 10.13 CPU) @ 2.67/s (n=27)
3:fail: 12.8325 wallclock secs (10.78 usr + 0.00 sys = 10.78 CPU) @ 266.58/s (n=2874)
3:match: 11.8457 wallclock secs (10.09 usr + 0.00 sys = 10.09 CPU) @ 9.31/s (n=94)
在这些情况下,失败很快。这似乎是由于Perl可能首先扫描所有普通的子匹配字符串,如果找不到那些字符串则会失败(与index
的速度相同)。