English 中文(简体)
应用许多Perl正则表达式测试的最佳方法是什么?
原标题:What s the best way to apply many Perl regular expression tests?
  • 时间:2010-10-23 04:36:27
  •  标签:
  • regex
  • perl

我有一个Perl模块,它将文本与数百个正则表达式的列表进行匹配;目前我只是在告诉他们:

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

有没有更好/更快/资源密集度更低的方法可以做到这一点?也许存在一个有用的模块,或者我应该将它们存储在散列中,等等。

最佳回答

看看Regexp::组装

这来自描述:

Regexp::Assemble接受任意数量的正则表达式,并将它们组装为一个正则表达式(或RE),该正则表达式与所有单个RE匹配。

因此,目标字符串只需要针对一个表达式进行测试,而不需要有一个大的表达式列表来循环。当你有几千个模式需要处理时,这很有趣。我们付出了巨大的努力来制造尽可能小的图案。

还可以跟踪原始图案,这样您就可以确定在形成组合图案的源图案中,哪一个是导致匹配发生的图案。

我在一些项目中使用了它,它非常棒。

问题回答

来自perlfaq6如何同时有效地匹配多个正则表达式


如何同时有效地匹配多个正则表达式?

(布赖恩·福伊供稿)

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

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

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

智能匹配在找到匹配时停止,因此不必尝试每个表达式。

早于Perl5.10,您还有一些工作要做。您希望避免每次想要匹配正则表达式时都编译它。在本例中,Perl必须为foreach循环的每次迭代重新编译正则表达式,因为它无法知道$pattern将是什么:

my @patterns = qw( foo bar baz );

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

qr//运算符出现在perl5.005中。它编译正则表达式,但不应用它。当您使用regex的预编译版本时,perl所做的工作较少。在这个例子中,我插入了一个映射,将每个模式转换为其预编译的形式。脚本的其余部分相同,但速度更快:

my @patterns = map { qr/$_/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 /(?:$regex)/i;
    }

有关正则表达式效率的更多详细信息,请参阅Jeffrey Freidl的《掌握正则表达式》。他解释了正则表达式引擎是如何工作的,以及为什么有些模式效率低得惊人。一旦您了解了perl是如何应用正则表达式的,就可以针对具体情况对它们进行调优。

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

用类似的东西把它们读进去

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

为了提高性能,我唯一的建议是使用真正的解析器ANTLR的perl目标似乎已经失效,但我使用通过perl的内联::Java在Java中生成的解析器时没有遇到任何问题。

编辑:确实考虑了另一件小事:将正则表达式从最常见匹配排列到最不常见匹配。可以给你一个小的持续因素改善。

如果您的regexp没有更改,那么您应该使用/o后缀,这将要求它们只编译一次。这将大大有助于提高速度。

此外,按照“最常见的拒绝优先”或“外卡最少的优先”对它们进行排序,这样之后的那些,更占用cpu的那些,执行频率最低。

当然可以从文件中读取它们,但为了提高速度,正确的方法是读取它们,然后在文本字符串中构造一个子例程,然后评估文本字符串以返回要调用的匿名子例程。这为您提供了硬编码regexp列表的速度优势以及regexp变量列表的灵活性。





相关问题
Why does my chdir to a filehandle not work in Perl?

When I try a "chdir" with a filehandle as argument, "chdir" returns 0 and a pwd returns still the same directory. Should that be so? I tried this, because in the documentation to chdir I found: "...

How do I use GetOptions to get the default argument?

I ve read the doc for GetOptions but I can t seem to find what I need... (maybe I am blind) What I want to do is to parse command line like this myperlscript.pl -mode [sth] [inputfile] I can use ...

Object-Oriented Perl constructor syntax and named parameters

I m a little confused about what is going on in Perl constructors. I found these two examples perldoc perlbot. package Foo; #In Perl, the constructor is just a subroutine called new. sub new { #I ...

Where can I find object-oriented Perl tutorials? [closed]

A Google search yields a number of results - but which ones are the best? The Perl site appears to contain two - perlboot and perltoot. I m reading these now, but what else is out there? Note: I ve ...

热门标签