【问题标题】:Raku/Perl6: How to restrict match method to capture group?Raku/Perl6:如何限制匹配方法以捕获组?
【发布时间】:2019-12-12 16:12:59
【问题描述】:

我正在尝试将文件名中的三个字母与 1000Genomes 项目匹配,并且仅匹配来自 ethnicity_lists/PEL.txt 之类的字符串的三个字母,我应该只得到 PEL。字符串的其余部分无关紧要。

my $p1-label = @populations[$p1-index].match(/^ethnicity_lists\/(<[A..Y]>)**3\.txt$/);

问题在于$p1-label 包含捕获组之外的整个字符串。

我在&lt;[A..Y]&gt; 周围加上括号,以强调我只想要那个组。

浏览https://docs.perl6.org/routine/match

我尝试尽可能具体以防止任何可能的错误,这就是我包含整个字符串的原因。

如果我进行 Perl5 风格的匹配:

if @populations[$p1-index] ~~ /^ethnicity_lists\/(<[A..Y]>)**3\.txt$/ {
    put $0.join(''); # strange that this outputs an array instead of a string
}

我已经尝试了match 方法的所有副词,但没有一个能完成必要的工作。

如何将match 方法限制为仅正则表达式中的捕获组?

【问题讨论】:

    标签: regex raku


    【解决方案1】:

    match 方法返回一个包含所有匹配信息的 Match 对象。如果你这样做:

    my $p1-label = @populations[$p1-index].match(/^ethnicity_lists\/(<[A..Y]>)**3\.txt$/);
    say $p1-label;
    

    您会看到它包含 3 个标记为 0 的项目,因为括号外提到了 **3:

    「ethnicity_lists/PEL.txt」
     0 => 「P」
     0 => 「E」
     0 => 「L」
    

    获取 Match 对象的 Str 表示可以为您提供完整的匹配。但你也可以要求它的[0] 索引。

    say  say $p1-label[0]'
    [「P」 「E」 「L」]
    

    让我们修复正则表达式,将量词放在括号中,看看我们得到了什么。

    my $p1-label = @populations[$p1-index].match(/^ethnicity_lists\/(<[A..Y]>**3)\.txt$/);
    say $p1-label;
    「ethnicity_lists/PEL.txt」
     0 => 「PEL」
    

    看起来更好。现在,如果您只想要PEL 位,您有两个选择。您可以获取匹配项中第一项的 Str 表示:

    my $p1-label = @populations[$p1-index].match(/^ethnicity_lists\/(<[A..Y]>**3)\.txt$/)[0].Str;
    say $p1-label;
    PEL
    

    请注意,如果我不将其强制为字符串,我将获得子匹配的匹配对象。 (这可能有用,但不是您需要的)。

    或者您可以使用零宽度断言并完全跳过捕获:

    my $p1-label = @populations[$p1-index].match(/<?after ^ethnicity_lists\/><[A..Y]>**3<?before \.txt$>/).Str;
    say $p1-label;
    PEL
    

    这里我们匹配出现在表达式^ethnicity_lists\/之前 \.txt$ 的3 个大写字母,但它们不包含在匹配项中。

    或者正如@raiph 所指出的,您可以使用双重捕获来告诉系统这是您想要的唯一位:

    my $p1-label = @populations[$p1-index].match(/^ethnicity_lists\/<(<[A..Y]>**3)>\.txt$/)[0].Str;
    say $p1-label;
    PEL
    

    最后一个可能是最好的。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      @Holli 的回答提出了一个关键点,@Scimon 深入挖掘了为什么你得到了你得到的结果,但是......

      如果您双重&lt;( ... )&gt;而不是( ... )强调您想要的部分,它只会使该部分成为整体捕获对象。

      如果您使用put 而不是say,您将获得机器友好 字符串化(与.Str 相同,因此在本例中为PEL)而不是人类友好的 字符串化(与.gist 相同,所以在这种情况下应该是「PEL」):

      put 'fooPELbar' ~~ / foo  ( ... )  bar /; # fooPELbar
      put 'fooPELbar' ~~ / foo <( ... )> bar /; # PEL
      

      【讨论】:

      • 谢谢@Holli。 :) .oO(我非常高兴)
      • 呜呜呜。我错过了。惊人的。 (我将其添加到我的答案中以使其更完整。希望您不介意)。
      • @Scimon 真棒。 :)
      【解决方案3】:

      它输出一个数组,因为捕获组匹配多次。您需要将量词放在组内:

      /^ethnicity_lists\/(<[A..Y]>**3)\.txt$/;
      say $0; # PEL
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-21
        • 1970-01-01
        相关资源
        最近更新 更多