Perl - 结合多个正则表达式而无需重新编号?

时间:2017-05-20 09:27:33

标签: regex perl

我需要将多个正则表达式组合成一个,所以代码看起来像这样:

my $s = "jump 0xbdf3487";
#my $s = "move 0xbdf3487";                                                                                         

if ($s =~ m/^(move) ([^ ]+)/) {  print "matched '$1' '$2'\n";  }
if ($s =~ m/^(jump) ([^ ]+)/) {  print "matched '$1' '$2'\n";  }
if ($s =~ m/^(call) ([^ ]+)/) {  print "matched '$1' '$2'\n";  }

变为:

my $s = "jump 0xbdf3487";
#my $s = "move 0xbdf3487";                                                                                         

my @patterns = (
    '^(move) ([^ ]+)',
    '^(jump) ([^ ]+)',
    '^(call) ([^ ]+)'
  );

my $re = "(?:" . join("|", @patterns) . ")";
$re = qr/$re/;

if ($s =~ m/$re/) {  print "matched '$1' '$2'\n";  }

但是,如果$s是我们获得的跳转,那么这不起作用:

matched '' ''

组合正则表达式中的匹配重新编号:
(1美元,2美元)在跳跃正则表达式($ 5,$ 6)中变成(3美元,4美元),等等。

如何在不重新编号的情况下组合这些?

3 个答案:

答案 0 :(得分:6)

使用分支重置模式(?|pattern)(您需要Perl 5.10或更新版本)。引用文档(perldoc perlre):

  

这是“分支重置”模式,它具有捕获组从每个交替分支中的相同起点编号的特殊属性。

您的代码变为:

use strict; 
use warnings;

my $s = "jump 0xbdf3487";
#my $s = "move 0xbdf3487";                                                                                         

my @patterns = (
    '(move) ([^ ]+)',
    '(jump) ([^ ]+)',
    '(call) ([^ ]+)'
  );

my $re = "^(?|" . join("|", @patterns) . ")";
$re = qr/$re/;
if ($s =~ m/$re/) {  print "matched '$1' '$2'\n";  }

请注意,我已添加use strictuse warnings,请勿忘记!

答案 1 :(得分:4)

您可以在正则表达式中使用简单的替换,只使用一个正则表达式:

m/^(move|jump|call) ([^ ]+)/

<强>代码:

my $s = "jump 0xbdf3487";

if ($s =~ m/^(move|jump|call) ([^ ]+)/) {
   print "matched '$1' '$2'\n";
}

答案 2 :(得分:1)

Perl Regex子模式可以通过管道连接在一起,使它们交替出现模式。要将交替模式与表达模式的其余部分分开,请将它们分组为一个组。如果您不想捕获该组匹配的内容,请将其设为非捕获组。

例如,在模式中的捕获组中进行更改:

(move|jump|call) ([^ ]+)

在模式中的非捕获组中进行交替:

(?:move|jump|call) ([^ ]+)

如果您的替代模式很复杂,并且您不希望它们全部在一行上,则可以使用/ x修饰符将它们与空格分开。

Perldoc PerlRe Modifiers(向下滚动到“某些修饰符的详细信息”)

  

/ X

     

/ x告诉正则表达式解析器忽略大多数空格   既不是倒退也不是在括号内的角色类中。您可以   用这个来将你的正则表达式分解成(略微)更多   可读部分。此外,“#”字符被视为元字符   引入一个满足模式结束分隔符的注释,   如果图案延伸到下一个图案,则到当前行的末尾   线。因此,这非常像普通的Perl代码注释。   (只有在您的情况下,您才可以在注释中包含结束分隔符   在它前面加一个反斜杠,所以要小心!)

     

使用/ x表示如果你想要真正的空格或“#”字符   模式(在括号内的字符类之外,不受影响   通过/ x),那么你要么必须逃避它们(使用反斜杠或   \ Q ... \ E)或使用八进制,十六进制或\ N {}转义对它们进行编码。它是   尝试继续评论到下一行是无效的   使用反斜杠或\ Q。

转义\ n

这是我的例子,证明:

#!/usr/bin/perl

use strict;
use warnings;

my $s = "jump 0xbdf3487";

if ($s =~ /^(

          move   # first complicated pattern

          |

          jump   # second complicated pattern

          |

          call   # third complicated pattern

    )\s([^\ ]+) /x) {   # Note I hade to escape the space
                        # with a backslash because of /x

    print "matched '$1' '$2'\n";
}

哪个输出:

matched 'jump' '0xbdf3487'