如何访问比赛中的捕获?

lis*_*tor 5 regex match named raku

我正在尝试解析 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];
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 5

补充克里斯托夫回答的详细讨论

\n
\n

我正在尝试解析 csv 文件

\n
\n

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

\n
\n

我正在尝试访问命名的正则表达式

\n
\n

如果您正在学习 Raku 解析,请利用很棒的相关(免费)开发人员工具[2]

\n
\n

在 Raku 的原始正则表达式中

\n
\n

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

\n

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

\n

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

\n

为了了解发生了什么,我将首先模拟您尝试执行的操作。我将使用一个正则表达式来声明一个捕获,即与字符串匹配的“命名”(又名“关联”)捕获ab

\n
given \'ab\'\n{\n    my $m1 = m/ $<named-capture> = ( ab ) /;\n\n    say $m1<named-capture>;\n    # \xef\xbd\xa2ab\xef\xbd\xa3\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n

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

\n

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

\n
given \'ab\'\n{\n    my $m1 = m/ ( $<named-capture> = ( ab ) ) /; # extra parens added\n\n    say $m1[0]<named-capture>;\n    # \xef\xbd\xa2ab\xef\xbd\xa3\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

的匹配结果$<named-capture> = ( ab )随后存储在 内 $m1[0]。这就是为什么say $m1[0]<named-capture>有效。

\n

到目前为止,一切都很好。但这只是故事的一半......

\n

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

\n

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

\n
given \'ab\'\n{\n    my $m1 = m/ ( $<named-capture> = ( ab ) )* /; # * is a quantifier\n\n    say $m1[0][0]<named-capture>;\n    # \xef\xbd\xa2ab\xef\xbd\xa3\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

概括

\n
    \n
  • 捕获巢穴;

    \n
  • \n
  • *通过或量化的捕获+对应于两层嵌套,而不仅仅是一层。

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

    \n
  • \n
\n
\n

[1]安装相关模块并在代码开头写入use Text::CSV;(对于纯 Raku 实现)或(对于 Perl 加 XS 实现)。use Text::CSV:from<Perl5>;演讲幻灯片(单击顶部单词,例如“csv”,以浏览幻灯片)、视频Raku 模块Perl XS 模块。)

\n

[2]安装CommaIDE并享受其出色的语法/正则表达式开发/调试/分析功能。或者安装Grammar::Tracer;和/或Grammar::Debugger模块并在代码开头编写use Grammar::Tracer;或(演讲幻灯片视频模块。)use Grammar::Debugger;

\n

  • 非常感谢你,雷夫!经过您的详细解释,我现在看到了我的问题。非常感谢您的参与 !!! (2认同)
  • 谢谢雷夫。这是您对命名/编号捕获和匹配对象树之间关联的解释,以及 perl6 使用 * 构造一个列表而不是单个对象的事实。再次感谢! (2认同)