如果我有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。
答案 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