如何在Perl中的数组中存储正则表达式捕获?

时间:2010-02-21 02:56:07

标签: regex perl arrays

我正在尝试在Perl中使用正则表达式。我想知道是否可以将表达式的所有匹配存储到数组中?我知道我可以使用以下内容:($1,...,$n) = m/expr/g;但似乎只有在您知道要查找的匹配项数时才能使用它。我尝试了my @array = m/expr/g;,但这似乎不起作用。

感谢您的帮助!

7 个答案:

答案 0 :(得分:74)

如果您正在进行全局匹配(/g),则列表上下文中的正则表达式将返回所有捕获的匹配项。只需:

my @matches = ( $str =~ /pa(tt)ern/g )

此命令例如:

perl -le '@m = ( "foo12gfd2bgbg654" =~ /(\d+)/g ); print for @m'

给出输出:

12
2
654

答案 1 :(得分:17)

请参阅“在列表上下文中匹配”下的perldoc perlop手册条目:

  

如果未使用/ g选项,则列表上下文中的m //将返回包含的列表   子表达式与模式中的括号匹配,即($ 1,$ 2,$ 3 ......)

     

/ g修饰符指定全局模式匹配 - 即匹配次数   可能在字符串中。它的行为取决于上下文。在列表上下文中,它   返回正则表达式中任何捕获括号匹配的子字符串列表。如果没有括号,则返回所有匹配字符串的列表,就好像整个模式周围有圆括号一样。

您可以通过分配数组或以其他方式在列表上下文中执行评估来获取所有匹配项:

my @matches = ($string =~ m/word/g);

答案 2 :(得分:17)

有时您需要全局获取所有匹配项,例如PHP preg_match_all。如果是你的情况,那么你可以写一些类似的东西:

# a dummy example
my $subject = 'Philip Fry Bender Rodriguez Turanga Leela';
my @matches;
push @matches, [$1, $2] while $subject =~ /(\w+) (\w+)/g;

use Data::Dumper;
print Dumper(\@matches);

打印

$VAR1 = [
          [
            'Philip',
            'Fry'
          ],
          [
            'Bender',
            'Rodriguez'
          ],
          [
            'Turanga',
            'Leela'
          ]
        ];

答案 3 :(得分:8)

我认为这是一个不言自明的例子。注意第一个正则表达式中的/g修饰符:

$string = "one two three four";

@res = $string =~ m/(\w+)/g;
print Dumper(@res); # @res = ("one", "two", "three", "four")

@res = $string =~ m/(\w+) (\w+)/;
print Dumper(@res); # @res = ("one", "two")

请记住,您需要确保左值位于列表上下文中,这意味着您必须用括号括起标量值:

($one, $two) = $string =~ m/(\w+) (\w+)/;

答案 4 :(得分:0)

请注意,如果您知道每个匹配所需的捕获组的数量,可以使用此简单方法,以我为例(2个捕获组)。

假设您有一些“数据”之类的

my $mess = <<'IS_YOURS';
Richard     Rich
April           May
Harmony             Ha\rm
Winter           Win
Faith     Hope
William         Will
Aurora     Dawn
Joy  
IS_YOURS

使用以下正则表达式

my $oven = qr'^(\w+)\h+(\w+)$'ma;  # skip the /a modifier if using perl < 5.14

我可以在下面的@box中捕获全部12个(6对,不是 8个...和解,而乔伊失踪了。)

my @box = $mess =~ m[$oven]g;

如果我想“散布”盒子的细节,我可以这样做:

my %hash = @box;

或者我可以完全跳过该框,

my %hash = $mess =~ m[$oven]g;

请注意,%hash包含以下内容。订单丢失,重复密钥(如果存在)被压缩:

(
          'April'   => 'May',
          'Richard' => 'Rich',
          'Winter'  => 'Win',
          'William' => 'Will', 
          'Faith'   => 'Hope',
          'Aurora'  => 'Dawn'
);

答案 5 :(得分:0)

令我惊讶的是,这里没有提到,但是perl documentation provides带有标准变量@+。引用文档中的内容:

此数组保存当前活动动态范围中最后一次成功子匹配的开始的偏移量。

因此,要获取第一次捕获的值,可以这样写:

print substr( $str, $-[1], $+[1] - $-[1] ), "\n"; # equivalent to $1

另外,还有一个非常漂亮的标准变量%-,因为它不仅包含命名捕获,而且允许将重复的名称存储在数组中。

使用文档中提供的示例:

/(?<A>1)(?<B>2)(?<A>3)(?<B>4)/

将产生带有以下内容的哈希:

$-{A}[0] : '1'
$-{A}[1] : '3'
$-{B}[0] : '2'
$-{B}[1] : '4'

答案 6 :(得分:0)

是否可以将正则表达式的所有匹配项存储到数组中?

是的,在Perl 5.25.7中,添加了变量@{^CAPTURE},该变量包含“上一次成功模式匹配的捕获缓冲区的内容(如果有)”。这意味着即使捕获组的数目未知,它也包含($1, $2, ...)

在Perl 5.25.7(从5.6.0版本开始)之前,您可以使用@Jaques在其答案中建议的使用@-@+构建相同的数组。您将必须执行以下操作:

    my @capture = ();
    for (my $i = 1; $i < @+; $i++) {
        push @capture, substr $subject, $-[$i], $+[$i] - $-[$i];
    }