如何在Perl中匹配多个正则表达式?

时间:2010-09-12 09:19:33

标签: regex perl

我想检查一些字符串是否与给定的一组正则表达式匹配。我怎么能这样做?

5 个答案:

答案 0 :(得分:20)

如果您使用的是perl版本5.10或更高版本,请使用智能匹配!

#! /usr/bin/env perl

use warnings;
use strict;

use feature 'switch';

my @patterns = (
  qr/foo/,
  qr/bar/,
  qr/baz/,
);

for (qw/ blurfl bar quux foo baz /) {
  no warnings 'experimental::smartmatch';
  print "$_: ";
  given ($_) {
    when (@patterns) {
      print "hit!\n";
    }
    default {
      print "miss.\n";
    }
  }
}

虽然您没有看到明确的~~运算符,Perl's given/when会在幕后执行:

  

大部分力量来自隐式智能匹配,有时可以应用。大多数情况下,when(EXPR)被视为$_的隐式智能匹配,即$_ ~~ EXPR。 (有关智能匹配的更多信息,请参阅Smartmatch Operator in perlop。)

“Smartmatch Operator” in perlop提供了您可以使用的许多组合的表格,上面的代码对应于$a 任何$b数组,大致对应

grep $a ~~ $_, @$b

除了搜索短路之外,在匹配时快速返回,而不是处理所有元素。在隐式循环中,我们智能匹配任何 Regex ,这是

$a =~ /$b/

输出:

blurfl: miss.
bar: hit!
quux: miss.
foo: hit!
baz: hit!

附录

由于这个答案最初编写,Perl的设计师已经意识到智能匹配的工作方式存在错误,因此它是now considered an experimental feature。上面使用的案例不是有争议的用途之一,尽管如此,除了我添加given is experimental之外,代码的输出还包括when is experimentalno warnings 'experimental::smartmatch';

任何使用实验性功能都会带来一些风险,但我估计这种情况的可能性很小。当使用类似于上面的代码并升级到更新版本的Perl时,这是一个潜在的问题需要注意。

答案 1 :(得分:12)

perlfaq6回答How do I efficiently match many regular expressions at once?,在这种情况下,我刚刚使用智能匹配示例更新了最新的开发版本。


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

(由brian d foy提供)

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

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

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

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

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

my @patterns = qw( foo bar baz );

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

C运营商出现在perl 5.005。它编译常规 表达式,但不适用它。当你使用预编译 正则表达式的版本,perl做的工作较少。在这个例子中,我插入了 C将每个模式转换为预编译形式。其余的 脚本是相同的,但速度更快:

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撰写的I.他解释了如何定期 表达式引擎工作以及为什么某些模式令人惊讶 效率低下。一旦你理解了perl如何应用正则表达式, 你可以针对个别情况调整它们。

答案 2 :(得分:10)

我一次性测试多个正则表达式的值是Regexp::Assemble,它将“将多个正则表达式组装成单个RE”,其方式比简单地执行{{1}更加智能和优化}}。默认情况下,您还可以检索匹配的文本部分,如果您需要知道匹配的模式,join '|', @regexps开关将提供该信息。它的性能非常好 - 在一个应用程序中,我用它来同时测试1700个模式 - 我还没有需要它不做的任何事情。

答案 3 :(得分:3)

我不确定你在寻找什么,但是那样的东西?

#!/usr/bin/perl
@regexes = ( qr/foo/ , qr/bar/ );
while ($line=<>){
  chomp $line;
  $match=0;
  for $re (@regexes){
    $match++ if ($line =~ $re);
  }
  print "$line matches $match regexes\n";
}

你也可以把它们全部编译成一个像这样的单一的:

#!/usr/bin/perl
@regexes = ( qr/foo/ , qr/bar/ );
$allre= "(".join("|",@regexes).")";
$compiled=qr/$allre/;
while(<>){
  chomp;
  print "$_ matches ($1)\n" if /$compiled/;
}

希望有所帮助。

答案 4 :(得分:3)

如果使用大量regexp,您可能会对Regexp::Optimizer

感兴趣

从概要部分看:

use Regexp::Optimizer;
my $o  = Regexp::Optimizer->new;
my $re = $o->optimize(qr/foobar|fooxar|foozap/);
# $re is now qr/foo(?:[bx]ar|zap)/

如果您愿意安装额外的模块,那可能会更有效率。