Raku/Perl6: 如何将匹配方法限制为捕获组?

Raku/Perl6: How to restrict match method to capture group?

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

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

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

我在 <[A..Y]> 两边加上括号是为了强调我只想要那个组。

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

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

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

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

我已经尝试了 match 方法的所有副词,但 none 做了必要的工作。

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

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

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

匹配方法 returns 一个匹配对象,包含有关您的匹配的所有信息。如果你这样做:

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] index.

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

这里我们匹配出现在 after 表达式 ^ethnicity_lists\/before \.txt$ 的 3 个大写字母但它们不包含在比赛本身中。

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

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

最后一个可能是最好的。

希望对您有所帮助。

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

如果你双重<( ... )>而不是( ... )强调你想要的部分,它会使那个部分成为整体捕获对象。

如果您使用 put 而不是 say,您将得到 机器友好的 字符串化(与 .Str 相同,所以在这种情况下PEL) 而不是 human friendly 字符串化(与 .gist 相同,所以在这种情况下应该是 「PEL」):

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