TL;DR 如果您的 rule 创建了该方法所期望的数据结构,那么您的操作方法将起作用。因此,我们将修复 rule 并保留该方法。
主要问题
让我们假设EX1 规则被插入到一个工作语法中;一个字符串被成功解析;子字符串ex2/ex2/ex2 匹配EX1 规则;我们已经显示了解析树的相应部分(只需saying 使用语法.parse 的结果):
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
注意无关的0 => 捕获以及第二个和第三个EX2s 如何在它们下面缩进并且相对于第一个EX2 缩进。相对于您的方法假设,这是错误的嵌套结构。
布拉德对主要问题的解决方案
正如 Brad++ 在他们对本答案第一个版本的评论中指出的那样,您可以简单地从组合和捕获的构造 ((...)) 切换到仅组合的构造 ([...])。
rule EX1 { <EX2> [ '/' <EX2>]* }
现在与上面相同的输入字符串对应的解析树片段是:
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
EX2 => 「ex2」
EX2 => 「ex2」
0 捕获消失了,EX2s 现在都是兄弟姐妹。有关 P6 nests 何时以及为何采用这种方式的进一步讨论,请参阅 jnthn's answer to Why/how ... capture groups?。
您的操作方法现在应该可以工作了——对于一些输入...
Håkon 对另一个可能问题的解决方案
如果 Brad 的解决方案适用于您希望它适用的某些输入(但不是全部),则部分问题可能是您的 rule 与 <EX2> 和 / 字符之间的匹配方式。
正如 Håkon++ 在他们的回答中指出的那样,您的 rule 的间距可能不符合您的要求。
如果您不希望图案中的间距很大,请不要使用rule。在模式中的token 或regex all 空格(忽略字符串内部,例如' ')只是为了使您的模式更具可读性,并且相对于任何输入字符串没有意义匹配。如果有疑问,请使用token(或regex)而不是rule:
token EX1 { <EX2> ( '/' <EX2>)* }
? ? ? ? ? ?
? 指示的间距并不重要。您可以省略或扩展它,它不会影响规则如何匹配输入。这只是为了便于阅读。
相比之下,rule 构造的全部要点是模式中每个原子和每个量词后面的空格是significant。这种间距在输入中的相应子字符串之后隐式应用(用户可覆盖的)边界匹配规则(默认情况下,允许空格和/或“单词”和非“单词”字符之间的转换的规则)。
在您的 EX1 规则中,我在下面重复夸大间距以确保清晰,一些间距不显着,就像它不在 token 或 @987654360 中一样@:
rule EX1 { <EX2> ( '/' <EX2>)* }
? ? ?
和以前一样,? 表示不重要的间距——您可以省略或扩展它,它不会有任何区别。要记住的是,模式(或子模式)的 start 处的空格只是为了便于阅读。 (使用经验表明,如果将任何间距不视为显着,则效果会更好。)
但间隔或缺少间隔在原子或量词之后很重要:
This spacing is significant: ⮟ ⮟ ⮟
rule EX1 { <EX2> ( '/' <EX2>)* }
This LACK of spacing is significant: ⮝⮝
通过写你的 rule 你告诉 P6 只匹配输入与边界匹配(默认情况下允许空白):
所以你的规则告诉 P6 允许 / 和 <EX2> 之间的空格匹配当它们以该顺序出现时 -- /,然后是<EX2>。
但它也告诉 P6 不允许相反的空格 - 在<EX2> 匹配和/ 匹配之间那个顺序!除了第一对<EX2> '/'!! P6 将允许您声明任意复杂的匹配模式,包括间距,但我怀疑这是您的意思或想要的。
有关“原子之后”含义的完整列表(即当rules 中的空格很重要时)请参阅When is white space really important in Perl6 grammars?。
这个重要的间距特征是:
经典 Perl DWIMery 旨在让生活更轻松;
惯用语——用于大多数语法,因为它确实确实让生活更轻松;
rule 声明符存在的唯一原因(这一重要的空白方面是唯一rule 和token 之间的区别);
完全可选,因为您可以改用token。
如果阅读本文的人认为他们不想利用这一重要的空间功能,那么他们可以改用tokens。 (这反过来可能会引导他们了解为什么 rule 存在作为一个选项,然后,或者可能稍后,了解它为什么会这样工作,并重新欣赏它的 DWIMery。:)
您要匹配的模式的内置构造
最后,这是编写您尝试匹配的模式的惯用方式:
rule EX1 { <EX2> + % '/' }
这告诉 P6 匹配一个或多个由/ 字符分隔的<EX2>s。请参阅 Modified quantifier: %, %% 了解有关这个不错的构造的说明。
这仍然是rule,因此其中的大部分间距仍然很重要。 The precise details for when it is and isn't 显然最适合这个结构,因为它最多有三个重要的间隔,而一个没有:
NOT significant: ⮟ ⮟
rule EX1 { <EX2> + % '/' }
Significant: ⮝ ⮝ ⮝
在+ 之后的 和 之前都包含空格是多余的:
rule EX1 { <EX2> + % '/' }
rule EX1 { <EX2> +% '/' } # same match result
rule EX1 { <EX2>+ % '/' } # same match result