命名捕获组可以匹配多次(Perl)

7
当我运行这段代码时:
$_='xaxbxc';
if(/(x(?<foo>.))+/) {
    say "&: ", $&;
    say "0: ", $-{foo}[0];
    say "1: ", $-{foo}[1];
 }

我得到:

&: xaxbxc
0: c
1:

我知道这是它应该工作的方式,但我希望能够以某种方式获取所有匹配项的列表('a', 'b', 'c'),而不仅仅是最后一个匹配项(c)。我该怎么做?


类似于这个问题 - Cameron
5个回答

5
在这种情况下,使用嵌入代码块可以提供一个简单的解决方案:
my @match;
$_='xaxbxc';
if(/((?:x(.)(?{push @match, $^N}))+)/) {
    say "\$1: ", $1;
    say "@match"
}

它将打印:

$1: xaxbxc
a b c

是的,最终我使用了这个作为我的解决方案...但回溯问题很棘手...我不得不将我的代码块移动得更远离捕获,以确保在回溯期间不会调用它。 - JoelFan

4

我认为通常情况下没有一种方法可以做到这一点(如果我错了,请纠正我),但在特定情况下可能有一种实现相同目标的方法。例如,对于您的特定代码示例,可以采用以下方法:

$_='xaxbxc';
while (/x(?<foo>.)/g) {
    say "foo: ", $+{foo};
}

你究竟想要达到什么目的?也许即使无法进行重复捕获,我们仍然可以为您的实际问题找到解决方法。


2
Perl允许正则表达式在末尾使用"g"开关时多次匹配。然后可以循环处理每个单独匹配,具体描述在Perl正则表达式教程中的全局匹配小节中:Using Regular Expressions in Perl
while(/(x(?<foo>.))+/g){
    say "&: ", $&;
    say "foo: ", $+{foo};
}

这将生成一个迭代列表:
&: xa
foo: a
&: xb
foo: b
&: xc
foo: c

虽然还不完全符合您的要求,但已经非常接近了。将全局正则表达式(/g)与您之前的本地正则表达式结合起来可能会做到这一点。通常,将捕获组放在重复组周围,然后使用表示该组的单个迭代的全局正则表达式重新解析该组,并对其进行迭代或将其用作列表。

看起来这个问题与这个问题非常相似-至少在答案上是如此,如果不是在公式化上-有人比我更擅长Perl回答了这个问题:"是否有Perl等效于Python的re.findall/re.finditer(迭代正则表达式结果)?" 您可能还想检查那个答案,其中更详细地介绍了全局正则表达式的正确使用方法。(Perl不是我的语言,我只是对正则表达式有一种不健康的欣赏。)


1

%-变量用于在同一模式中有多个相同命名组时使用,而不是当给定组恰好被迭代时使用。

这就是为什么/ (.) + / 不会将每个单独的字符加载到 $1 中,只会加载最后一个字符。 / (<x>.) + / 也是如此。但是,对于/(<x>.)(<x>.)/,您有两个不同的<x>组,因此$-{x}。请考虑:

% perl -le '"foobar" =~ /(?<x>.)(?<x>.)/; print "x#1 is $-{x}[0], x#2 is $-{x}[1]"'
x#1 is f, x#2 is o

% perl -le '"foobar" =~ /(?:(?<x>.)(?<x>.))+/; print "x#1 is $-{x}[0], x#2 is $-{x}[1]"'
x#1 is a, x#2 is r

-1

我不确定那是否正是你所寻找的,但以下代码应该能解决问题。

$_='xaxbxc';
@l = /x(?<foo>.)/g;

print join(", ", @l)."\n";

但是,我不确定这是否适用于重叠的字符串。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接