Perl正则表达式和捕获组

14
以下代码将输出 ac | a | bbb | c
    #!/usr/bin/env perl
    use strict;
    use warnings;
    # use re 'debug';
    
    my $str = 'aacbbbcac';
    
    if ($str =~ m/((a+)?(b+)?(c))*/) {
       print "$1 | $2 | $3 | $4\n";
    }

似乎失败的匹配不会重置捕获组变量。 我错过了什么?


3
您期望什么样的输出结果? - Tomasz Nguyen
@ikegami 我知道,这不是我的模式,我在 G+ Perl 社区遇到了这个问题,想知道一下。 - snoofkin
此外,匹配失败不会重置捕获变量。perl -E'"a"=~/(.)/; "b"=~/(..)/; say $1;' - ikegami
3个回答

21
看起来好像匹配失败不会重置捕获组变量。
这里没有匹配失败。你的正则表达式能够成功匹配字符串。尽管一些重复部分中有一些内部组无法匹配成功。每个匹配的组可能会被下一个特定组的匹配覆盖,或者如果该组在当前重复中未匹配,则保留其来自前一个匹配的值。
我们来看看正则表达式匹配的过程:
- 首先,`(a+)?(b+)?(c)` 匹配 `aac`。由于 `(b+)?`是可选的,因此不会匹配。在这个阶段,每个捕获组包含以下部分:
- `$1` 包含整个匹配结果:`aac` - `$2` 包含 `(a+)?` 部分:`aa` - `$3` 包含 `(b+)?` 部分:`null` - `$4` 包含 `(c)` 部分:`c`
- 由于还剩下一些字符串需要匹配,即 `bbbcac`。继续进行匹配,`(a+)?(b+)?(c)` 匹配 `bbbc`。由于 `(a+)?` 是可选的,所以它不会被匹配。
- `$1` 包含整个匹配结果:`bbbc`,覆盖了 `$1` 中的先前值 - `$2` 不匹配。因此,它将包含以前匹配的文本:`aa` - `$3` 这一次匹配成功。它包含 `bbb` - `$4` 匹配 `c`
  • 再次说明,(a+)?(b+)?(c)将继续匹配尾部的- ac

    • $1 包含整个匹配 - ac
    • $2 这次匹配了 a。覆盖了$2之前的值。现在它包含 - a
    • $3 这次没有匹配,因为没有 (b+)? 部分。它将与上一次匹配相同 - bbb
    • $4 匹配了 c。覆盖了之前匹配中的值。现在它包含 - c
  • 现在,字符串中没有剩下的部分可以匹配。所有捕获组的最终值是:

    • $1 - ac
    • $2 - a
    • $3 - bbb
    • $4 - c

    2

    虽然看起来很奇怪,但这是“预期”的行为。以下是来自perlre文档的引用:

    注意:在Perl中失败的匹配不会重置匹配变量,这使得编写测试一系列更具体情况并记住最佳匹配的代码更容易。


    -1
    对于括号分组,/(\d+)/ 这个 文档 建议使用 \1 \2 ... 或者 \g{1} \g{2}。在替换正则表达式部分使用 $1 or $2... 会导致一个错误,如:模式中找到标量
    # Example to turn a css href to local css.
    # Transforms <link href="http://..." into <link href="css/..."
    
    # ... inside a loop ...
    
    my $localcss = $_; # one line from the file
    $localcss =~ s/href.+\/([^\/]+\.css")/href="css\/\1/g ;
    

    不分开,那要怎么办才能得到答案呢? - Toto
    所有对于$1 $2的使用在这之上都会导致Perl标量崩溃。感谢提醒。 - Sergio Abreu
    2
    你在哪里看到的?\1是用于正则表达式模式内部的反向引用,而$1是包含第一组值的变量,它用于替换部分或正则表达式外部,它们是两个不同的概念。 - Toto
    1
    我来到这个页面是因为我需要在替换中使用反向引用\1。其他人也会感慕您的帮助。感谢您的关注。 - Sergio Abreu
    链接的文档明确指出在您的情况下不要使用\1,它只有在某些情况下才能正常工作:“这是因为在PerlThink中,s///的右侧是一个双引号字符串。\1在通常的双引号字符串中表示控制-A。[...]您无法通过说{1}000来消除歧义,但您可以通过${1}000来修复它。” https://metacpan.org/pod/release/RJBS/perl-5.18.1/pod/perlre.pod#Warning-on-%5C1-Instead-of-$1 - Thorsten Schöning

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