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

con*_*con 4 regex raku

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

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

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

我已经把括号放在了<[A..Y]>强调我只想要那个组。

浏览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
}
Run Code Online (Sandbox Code Playgroud)

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

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

Sci*_*mon 7

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

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

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

?ethnicity_lists/PEL.txt?
 0 => ?P?
 0 => ?E?
 0 => ?L?
Run Code Online (Sandbox Code Playgroud)

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

say  say $p1-label[0]'
[?P? ?E? ?L?]
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

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

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

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

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

这最后一个可能是最好的。

希望有帮助。


Hol*_*lli 6

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

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


rai*_*iph 6

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

如果你加倍强调你想要的部分<( ... )>而不是仅仅( ... )让那部分成为整体捕获对象。

如果你使用put而不是say你得到机器友好的字符串化(与 相同.Str,在这种情况下PEL)而不是人类友好的字符串化(与 相同.gist,所以在这种情况下它会是?PEL?):

put 'fooPELbar' ~~ / foo  ( ... )  bar /; # fooPELbar
put 'fooPELbar' ~~ / foo <( ... )> bar /; # PEL
Run Code Online (Sandbox Code Playgroud)