我如何访问比赛中的捕获?

How do I access the captures within a match?

我正在尝试解析一个 csv 文件,并且正在尝试访问 Perl6 中原始正则表达式中的名称正则表达式。结果是零。正确的做法是什么?

grammar rsCSV {
    regex TOP { ( \s* <oneCSV> \s* \, \s* )* }
    proto regex oneCSV {*}
          regex oneCSV:sym<noQuote> { <-[\"]>*?  }
          regex oneCSV:sym<quoted>  { \" .*? \" } # use non-greedy match
}

my $input = prompt("Enter csv line: "); 

my $m1 = rsCSV.parse($input);
say "===========================";
say $m1;
say "===========================";
say "1 " ~ $m1<oneCSV><quoted>;  # this fails; it is "Nil"
say "2 " ~ $m1[0];
say "3 " ~ $m1[0][2];

<oneCSV> 的匹配位于捕获组的范围内,您可以通过 $m1[0].

获得该捕获组

由于组是用 * 量化的,结果将再次是一个列表,即您需要另一个索引操作来获取匹配对象,例如 $m1[0][0] 用于第一个。

然后可以通过名称访问命名的捕获,例如$m1[0][0]<oneCSV>。这将已经包含 protoregex 适当分支的匹配结果。

如果您想要整个匹配列表而不是特定的匹配列表,您可以使用 >>map,例如 $m1[0]>>.<oneCSV>.

补充 Christoph 回答的详细讨论

I am trying to parse a csv file

也许您正在专注于学习 Perl 6 解析并且正在编写一些一次性代码。但是如果你想要开箱即用的工业强度 CSV 解析,请注意 Text::CSV 模块[1].

I am trying to access a named regex

如果你正在学习Perl 6解析,请注意jnthn的语法跟踪器和调试器[2].

in proto regex in Perl6

您的问题与原始正则表达式无关。

相反,问题是,虽然与您命名的捕获 对应的匹配对象 存储在您存储在 $m1 中的整体匹配对象中,但它并未存储正是您要查找的位置。

捕获对应的匹配对象出现在哪里?

要了解发生了什么,我将从模拟您尝试执行的操作开始。我将使用一个只声明一个捕获的正则表达式,一个匹配字符串 ab.

的“命名”(又名“关联”)捕获
given 'ab'
{
    my $m1 = m/ $<named-capture> = ( ab ) /;

    say $m1<named-capture>;
    # 「ab」
}

与命名捕获对应的匹配对象存储在您可能希望它出现在 $m1 中的位置 $m1<named-capture>

但是 $m1<oneCSV> 你得到的是 Nil。给出了什么?

为什么你的 $m1<oneCSV> 不起作用

有两种捕获类型:命名(又名“关联”)和编号(又名“位置”)。您在 <oneCSV> 周围的正则表达式中编写的括号引入了 numbered 捕获:

given 'ab'
{
    my $m1 = m/ ( $<named-capture> = ( ab ) ) /; # extra parens added

    say $m1[0]<named-capture>;
    # 「ab」
}

/ ( ... ) / 中的括号声明单个顶级编号捕获。如果匹配,则对应的匹配对象存储在$m1[0]中。 (如果您的正则表达式看起来像 / ... ( ... ) ... ( ... ) ... ( ... ) ... /,那么与匹配第二对括号的内容对应的另一个匹配对象将存储在 $m1[1] 中,另一个存储在 $m1[2] 中,以此类推。)

然后$<named-capture> = ( ab )的匹配结果存储在里面$m1[0]。这就是 say $m1[0]<named-capture> 起作用的原因。

到目前为止一切顺利。但这只是故事的一半...

为什么您的代码中的 $m1[0]<oneCSV> 也不起作用

虽然上面代码中的 $m1[0]<named-capture> 有效,但您 仍然 无法在原始代码中的 $m1[0]<oneCSV> 中获得匹配对象。这是因为您还要求第 0 次捕获的 多个匹配项 因为您使用了 * quantifier:

given 'ab'
{
    my $m1 = m/ ( $<named-capture> = ( ab ) )* /; # * is a quantifier

    say $m1[0][0]<named-capture>;
    # 「ab」
}

因为 * 量词要求多个匹配项,Perl 6 将匹配对象的 列表 写入 $m1[0]。 (在这种情况下,只有一个这样的匹配,所以你最终得到一个长度为 1 的列表,即 $m1[0][0](而不是 $m1[0][1]$m1[0][2] 等)。)

总结

  • 夺巢;

  • 通过 *+ 量化的捕获对应于 两个 嵌套级别,而不仅仅是一个。

  • 在您的原始代码中,您必须编写 say $m1[0][0]<oneCSV>; 才能找到您要查找的匹配对象。


[1] 安装相关模块并写入 use Text::CSV;(对于纯 Perl 6 实现)或 use Text::CSV:from<Perl5>;(对于 Perl 5 plus XS 实现) 在代码的开头。 (talk slides (click on top word, eg. "csv", to advance through slides), video, Perl 6 module, Perl 5 XS module.)

[2]安装相关模块并在代码开头写上use Grammar::Tracer;use Grammar::Debugger;。 (talk slides, video, modules.)