代码之家  ›  专栏  ›  技术社区  ›  JoelFan

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

  •  5
  • JoelFan  · 技术社区  · 15 年前

    当我运行此代码时:

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

    我得到:

    &: xaxbxc
    0: c
    1:
    

    我知道这就是它应该如何工作的,但我想以某种方式得到所有匹配的列表 ('a', 'b', 'c') 而不是最后一场比赛( c )我该怎么做?

    5 回复  |  直到 15 年前
        1
  •  3
  •   Eric Strom    15 年前

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

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

    打印内容:

    $1: xaxbxc
    a b c
    
        2
  •  4
  •   Cameron    15 年前

    我不认为总的来说有一种方法可以做到这一点(如果我错了,请纠正我),但在特定情况下可能有一种方法可以实现相同的最终目标。例如,这对于您的特定代码示例是有效的:

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

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

        3
  •  3
  •   Community Mohan Dere    9 年前

    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
    

    这仍然不是你想要的,但它真的很接近。将全局regex(/g)与上一个本地regex组合可能会做到这一点。通常,在重复的组周围创建一个捕获组,然后用一个只表示该组的单个迭代的全局regex重新解析该组,并对其进行迭代或将其用作列表。

    这看起来像是一个与这个问题非常相似的问题——至少在答案中,如果不是否定的话——已经被比我更擅长Perl的人回答了: "Is there a Perl equivalent of Python's re.findall/re.finditer (iterative regex results)?" 您可能还需要检查这些问题的答案,以及有关正确使用全局正则表达式的更多详细信息。(Perl不是我的语言,我只是不健康地欣赏正则表达式。)

        4
  •  1
  •   tchrist    15 年前

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

    这就是为什么 /(.)+/ 不加载 $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
    
        5
  •  0
  •   kriss    15 年前

    我不确定这正是您要找的,但下面的代码应该可以做到这一点。

    $_='xaxbxc';
    @l = /x(?<foo>.)/g;
    
    print join(", ", @l)."\n";
    

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