2010-10-23 104 views
1

我有一个Perl模块,将文本与数百个正则表达式进行匹配;目前我只是oring他们:什么是应用许多Perl正则表达式测试的最佳方式?

if (
    /?:re1/ or 
    ... 
    /re200$/ 
) { return "blah"; } 

是否有更好/更快/更少资源密集型的方式来做到这一点?也许存在一个有用的模块,或者我应该将它们存储在散列中等。

+1

可能的重复[我如何有效地匹配Perl中的许多不同的正则表达式模式?](http://stackoverflow.com/questions/1478083/how-can-i-efficiently-match-many-different-regex-patterns -in-perl) – daxim 2010-10-23 14:43:01

回答

10

看看Regexp::Assemble

这是从该描述:

正则表达式::组装花费的正则表达式的任意数量,并将它们组装成一个单一的正则表达式(RE或)相匹配的所有各单独RE匹配。

因此,不需要大量的表达式循环,只需要针对一个表达式测试目标字符串。当你有几千种模式需要处理时,这很有趣。认真努力制作出尽可能小的图案。

也可以跟踪原始模式,以便确定组成模式的源模式中哪一个是导致匹配发生的模式。

我用它来做一些项目,它非常棒。

+1

我使用Regexp :: Assemble从澳大利亚地址列表中提取城镇名称。根据官方数据来源,这些数据大约有10,000个,而我必须提取城镇的代码速度令人难以置信。 – singingfish 2010-10-23 07:53:41

+0

它产生的正则表达式可以令人兴奋。 – 2010-10-23 09:48:44

+0

+1:你打败了我。我正在使用Regexp :: Assemble在拍摄时匹配1700左右的术语,它的工作原理*很棒*。 – 2010-10-23 10:27:14

1

您可以将您的正则表达式保存在单独的文件中,每行一个。它不会运行得更快,但代码会更清晰。

读他们喜欢的东西

my @patterns; 
while (<>) { 
    push @patterns, qr/$_/; 
} 

为了提高性能,我唯一的建议是使用一个真正的解析器。 ANTLR的perl目标似乎已不存在,但我没有遇到过使用通过perl的Inline::Java在Java中生成的解析器的麻烦。

编辑:没有想到另一件小事:从最常见匹配到最不常见匹配的顺序排列正则表达式。可以给你一个小的不变因素改进。

1

如果您的regexps没有改变,那么您应该使用/ o后缀,这将需要它们只被编译一次。这将极大地提高速度。

此外,可以通过“最常见的拒绝优先”或“最少通配的优先”来排序它们,以便稍后使用更多的CPU密集型应用程序的执行次数最少。

从文件中读取它们当然是可以的,但为了提高速度,正确的方法是先读取它们,然后在文本字符串中构造一个子例程,然后评估文本字符串以返回一个匿名子例程呼叫。这为您提供了硬编码regexps列表的速度优势,并具有可变列表的正则表达式的灵活性。

+0

qr //更方便,子代在5.5.3之前。 – 2010-10-23 09:55:54

7

从的perlfaq6答案How do I efficiently match many regular expressions at once?


如何有效地在一次匹配许多正则表达式?

(贡献的布赖恩·d FOY)

如果你有Perl 5.10或更高版本,这几乎是微不足道的。你对正则表达式对象的数组只是智能匹配:

my @patterns = (qr/Fr.d/, qr/B.rn.y/, qr/W.lm./); 

if($string ~~ @patterns) { 
    ... 
    }; 

当它找到一个匹配,所以它并没有去尝试每一个表情的智能匹配停止。

早于Perl 5.10,你有一些工作要做。你想避免每次你想匹配它时编译一个正则表达式。在这个例子中,perl的必须重新编译的正则表达式foreach循环的每次迭代,因为它没有办法知道$格局将是:

my @patterns = qw(foo bar baz); 

LINE: while(<DATA>) { 
    foreach $pattern (@patterns) { 
     if(/\b$pattern\b/i) { 
      print; 
      next LINE; 
      } 
     } 
    } 

的QR //运营商在Perl 5.005露面。它编译一个正则表达式,但不适用它。当你使用预编译版本的正则表达式时,perl的工作量会减少。在这个例子中,我插入一张地图将每个模式转换为预编译的形式。其余的脚本是相同的,但速度更快:

my @patterns = map { qr/\b$_\b/i } qw(foo bar baz); 

LINE: while(<>) { 
    foreach $pattern (@patterns) { 
     if(/$pattern/) 
      { 
      print; 
      next LINE; 
      } 
     } 
    } 

在某些情况下,您可能可以将多个模式制作为单个正则表达式。谨防需要回溯的情况。

my $regex = join '|', qw(foo bar baz); 

LINE: while(<>) { 
    print if /\b(?:$regex)\b/i; 
    } 

有关正则表达式效率的更多详细信息,请参阅掌握Jeffrey Freidl的正则表达式。他解释了正则表达式引擎是如何工作的以及为什么某些模式效率低得惊人。一旦你了解perl如何应用正则表达式,你可以调整它们以适应个别情况。

+0

因为在perl文档___中没有看到这个__,所以我应该把它拿走。顺便说一句,你列入“贡献”的严重性并不会丢失在我身上。感谢您的帮助! – mikewaters 2010-10-23 16:07:33

相关问题