我正在尝试优化将在特定目录树中的每个文件上运行正则表达式的脚本。所有组件都按预期工作,但我试图让正则表达式尽可能快地运行。
脚本在每个文件上运行许多正则表达式。我们正试图做这样的事情:
我们从YAML文件开始:
---
-
description: has foo
regex: foo
-
description: has bar
regex: bar
-
description: has foofoo
regex: foofoo
-
description: has barbar
regex: barbar
然后我们将文件读入一个数组(并通过qr //运行正则表达式字符串来编译它们),如下所示:
my @regex = @{LoadFile('yaml_file')};
foreach ( @regex ) { $_->{'regex'} = qr/$_->{'regex'}/ }
然后评估每个文件上的每个正则表达式
foreach my $r ( @regex ) {
if ( $slurped_file_text =~ /$r->{'regex'}/ ){
stuff;
}
}
我们发现上述方法比只扩展if / elsif语句要慢得多:
if( $slurped_file_text =~ /foo/ ){
stuff;
}elsif( $slurped_file_text =~ /bar/ ){
stuff;
}elsif( $slurped_file_text =~ /foofoo/ ){
stuff;
}elsif( $slurped_file_text =~ /barbar/ ){
stuff;
}
但是,这个if / elsif方法不是DRY,我们需要能够轻松地将regex添加到我们的列表中,而不必每次都编辑脚本代码。
在查看NYTProf的foreach做事方式之后,它表明花了大量的时间来调用main :: CORE :: regcomp。
在阅读了类似的问题之后,我们找到了o运算符,它应该表示自编译以来正则表达式没有改变,所以它不需要重新编译。那么我们尝试了这个(基本上只是将o添加到顶部代码中):
foreach my $r ( @regex ) {
if ( $slurped_file_text =~ /$r->{'regex'}/o ){
stuff;
}
}
这给了我们想要的速度,但它没有正确评估正则表达式。当匹配模式存在时,它不会返回true。
我知道o运算符不再被大量使用了,但是,如上所述,我们仍在使用perl v5.10.1,此版本的文档表明我们需要o运算符才能获得我们正在寻找的性能对
我的问题是这些:
非常感谢任何和所有帮助。
答案 0 :(得分:5)
循环版本比展开循环的版本慢的原因是因为总是检查循环版本中的每个正则表达式,但是只检查到在展开版本中找到匹配项。
my @regexs = map $_->{regex}, @{ LoadFile('yaml_file') };
for my $text (@texts) {
for my $regex (@regexs) {
if ($text =~ $regex) {
stuff;
last; <---- Missing
}
}
}
但是,由于您似乎并不关心哪个模式匹配,您应该只构建一个模式并进行编译。
my $pattern = join '|', map "(?:$_->{regex})", @{ LoadFile('yaml_file') };
my $regex = qr/$pattern/;
for my $text (@texts) {
if ($text =~ $regex) {
stuff;
}
}