是否有一种简单的方法可以从5.10之前的正则表达式中获取所有成功捕获的列表?

时间:2010-03-18 17:28:16

标签: regex perl

如果我有Perl 5.10,我知道正确的方法是使用命名捕获和values %+,但是在Perl 5.8.9中我怎样才能获得成功捕获的列表?我想出了两种方法都很糟糕:

#you need to list each possible match
my @captures = grep { defined } ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);

#ew, I turned on symbolic references 
{
    no strict 'refs';
    my @captures = map { defined $+[$_] ? $$_ : () } 1 .. $#+;
}

我发现第三个选项涉及(?{}),但它需要全局变量(因为闭包发生在编译时)并且正则表达式从合理清晰到不敬虔的混乱。

我找到的唯一选择是捕获整个匹配,然后使用另一组正则表达式来获取我想要的值(实际上我从其他正则表达式构建第一个正则表达式,因为没有充分的理由复制逻辑)。

我显然遗漏了一条重要的信息。我在标量上下文中使用正则表达式以及\G断言,因为正则表达式可以在匹配之间进行更改(其中一个标记会改变您从字符串中获取标记的方式)。有关为Perl 5.10编写的代码示例,请参阅this question,特别是this answer

2 个答案:

答案 0 :(得分:1)

您可以在

中使用@+@-
substr $var, $-[N], $+[N] - $-[N] # corresponds to $N

但如前所述,如果可以,请使用@list = grep defined, $var =~ /regex/表单。

答案 1 :(得分:0)

以下解决方案使用字符串eval,但我认为这是一种相当安全的方式。

更新:也许我仍然遗漏了一些内容,但是AFAICS,模式使用\G并且匹配在标量上下文中这一事实才重要,因为匹配的结果不能直接分配到@matches

事实上,下面的方法是Chas中第二种方法的变体。 OP在哪里使用了符号引用。恕我直言,使用符号引用或字符串eval是好的,因为它们以非常明确的方式发生。

#!/usr/bin/perl

use strict; use warnings;

my $text = <<EOT;
a
2 b
3 c 3
EOT

my $re = qr/([a-z])/;

while ( $text =~ /$re/g  ) {
    my @matches = grep defined, map eval "\$$_", 1 .. $#-;
    print "@matches\n";
    if ( $matches[0] eq 'a' ) {
        $re = qr/\G\s+([0-9])\s+([a-z])/;
        next;
    }
    if ( defined $matches[1] and $matches[1] eq 'b' ) {
        $re = qr/\G\s+([0-9])(?: ([a-z]))(?: ([0-9]))/;
        next;
    }
}

输出:

C:\Temp> jj
a
2 b
3 c 3