命名的捕获多次匹配(Perl)

时间:2010-11-23 16:46:15

标签: regex perl

当我运行此代码时:

$_='xaxbxc';
if(/(x(?<foo>.))+/) {
    say "&: ", $&;
    say "0: ", $-{foo}[0];
    say "1: ", $-{foo}[1];
 }

我明白了:

&: xaxbxc
0: c
1:

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

5 个答案:

答案 0 :(得分:4)

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

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

你到底想要完成什么?也许我们可以为您的实际问题找到解决方案,即使没有办法重复捕获。

答案 1 :(得分:3)

Perl允许正则表达式多次匹配“g”开关超过结尾。然后可以循环每个单独的匹配,如Using Regular Expressions in Perl section of the Perl Regex Tutorial的全局匹配子部分所述:

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

这将生成一个迭代列表:

&: xa
foo: a
&: xb
foo: b
&: xc
foo: c

哪个仍然不是你想要的,但它真的很接近。将全局正则表达式(/ g)与之前的本地正则表达式相结合可能会做到这一点。通常,在重复的组周围创建一个捕获组,然后使用仅表示该组的单个迭代的全局正则表重新解析该组,并迭代它或将其用作列表。

这看起来像一个与这个问题非常相似的问题 - 至少在答案中,如果不是在论坛中 - 已经被Perl比我更有能力的人回答:"Is there a Perl equivalent of Python's re.findall/re.finditer (iterative regex results)?"你可能想要检查答案关于正确使用全局正则表达式的更多细节。 (Perl不是我的语言,我对正则表达式不满意。)

答案 2 :(得分:3)

在这种情况下,使用嵌入式代码块提供了一种简单的方法:

my @match;
$_='xaxbxc';
if(/((?:x(.)(?{push @match, $^N}))+)/) {
    say "\$1: ", $1;
    say "@match"
}

打印:

$1: xaxbxc
a b c

答案 3 :(得分: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

答案 4 :(得分:0)

我不确定这正是您正在寻找的,但以下代码应该可以解决问题。

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

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

但是,我不确定这会对重叠的字符串起作用。