作为语法的一部分,我有:
rule EX1 { <EX2> ( '/' <EX2>)* }
在我的动作课中,我写了:
method EX1($/) {
my @ex2s = map *.made, $/.<EX2>;
my $ex1 = @ex2s.join('|');
#say "EX1 making $ex1";
$/.make($ex1);
}
因此,基本上,我只是试图将所有EX2
与它们之间的'|'
而不是'/'
联接在一起。但是我的代码有些不对劲,因为它只选择第一个EX2
,而不是后面的。如何找出可选的是什么?
答案 0 :(得分:10)
TL; DR 如果您的rule
创建了该方法所期望的数据结构,则该操作方法将起作用。因此,我们将修复rule
并保留该方法。
让我们假设EX1
规则被放入有效的语法中;字符串已成功解析;子字符串ex2/ex2/ex2
与EX1
规则匹配;并且我们已经显示了解析树的相应部分(通过使用语法仅say
来.parse
的结果):
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
0 => 「/ex2」
EX2 => 「ex2」
请注意无关的0 =>
捕获,以及第二个和第三个EX2
在它们下面的缩进以及相对于第一个EX2
的缩进。相对于方法的假设,这是错误的嵌套结构。
正如Brad ++在回应此答案的第一个版本的评论中指出的那样,您可以简单地从既分组又捕获((...)
)的结构切换到仅分组([...]
的结构。 )。
rule EX1 { <EX2> [ '/' <EX2>]* }
现在,与上述相同的输入字符串对应的解析树片段为:
EX1 => 「ex2/ex2/ex2」
EX2 => 「ex2」
EX2 => 「ex2」
EX2 => 「ex2」
0
的捕获已消失,EX2
现在都是同级的。有关何时以及为什么P6 <嵌套>嵌套捕获其方式的进一步讨论,请参见jnthn's answer to Why/how ... capture groups?。
您的操作方法现在应该可以工作-适用于一些输入...
如果布拉德(Brad)的解决方案适用于您希望它能用于某些输入(但不是全部)的问题,则部分问题可能是您的rule
在<EX2>
和{{1 }}字符。
正如Håkon++在他们的答案中指出的那样,您的/
的间距可能无法满足您的要求。
如果您不希望图案中的间距很大,请不要使用rule
。在rule
或token
中,模式中的 all 空间(忽略字符串,例如regex
中的空格)只是为了使您的模式更具可读性,而且没有意义。相对于任何匹配的输入字符串。如有疑问,请使用' '
(或token
)而不是regex
:
rule
用token EX1 { <EX2> ( '/' <EX2>)* }
? ? ? ? ? ?
指示的间距不重要。您可以忽略它或对其进行扩展,这对规则与输入的匹配方式没有影响。这只是出于可读性。
相反,?
构造的要点是模式中每个原子和每个量词之后的空白为significant。这样的间距在输入中的相应子字符串之后隐式应用了(用户可重写)边界匹配规则(默认情况下,该规则允许空格和/或“ word”和非“ word”字符之间的过渡)。
在您的rule
规则中,为确保清晰起见,我在下面重复使用夸张的空格来重复该规则,其中某些空格不有效,就像在{{1}中不一样}或EX1
:
token
与以前一样,regex
表示的间距并不重要-您可以省略或扩展它,并且不会有任何区别。要记住的是,模式(或子模式)的 start 处的空格仅用于可读性。 (使用经验表明,将不的任何间距都视为有效间距会更好。)
但是原子或量词后的间距或缺少间距很重要:
rule EX1 { <EX2> ( '/' <EX2>)* }
? ? ?
通过像编写代码那样编写?
来告诉P6仅将输入与边界匹配(默认情况下允许空白)匹配:
之后第一 This spacing is significant: ⮟ ⮟ ⮟
rule EX1 { <EX2> ( '/' <EX2>)* }
This LACK of spacing is significant: ⮝⮝
(因此,之前 第一 {{ 1}});
rule
和后续<EX2>
之间的匹配项;
/
比赛之后的。
因此,您的规则要求P6允许/
和<EX2>
之间的空格匹配当它们以该顺序出现时-<EX2>
,然后是{{1 }}。
但是它也告诉P6 不允许以其他方式允许空格-在中的/
匹配和<EX2>
匹配之间订购!除了第一对/
之外!! P6可让您声明任意复杂度(包括空格)的匹配模式,但是我怀疑这是您的意思或想要的。
有关“在原子之后”的含义的完整列表(即<EX2>
中的空格很重要时),请参见When is white space really important in Perl6 grammars?。
此重要的间距功能是:
经典Perl DWIMery旨在简化生活;
惯用语-在大多数语法中使用,因为它确实使生活更轻松;
<EX2>
声明符存在的唯一原因(这个重要的空白是/
和<EX2> '/'
之间的 only 区别); < / p>
完全可选,因为您可以只使用rule
。
如果阅读此内容的人认为他们不愿意利用这一重要的空间功能,那么他们可以只使用rule
来代替。 (这反过来可能会导致他们了解为什么rule
作为一个选项存在,然后,或者也许以后,看看为什么它以这种方式工作,并重新欣赏其DWIMery。:))>
最后,这是编写您要匹配的模式的惯用方式:
token
这告诉P6匹配由token
个字符分隔的一个或多个token
。请参见Modified quantifier: %
, %%
,以获取有关此良好构造的说明。
这仍然是rule
,因此其中的大部分间距仍然很大。 The precise details for when it is and isn't显然最适合此构造,因为它最多具有三个重要的间隔,而一个不是:
rule EX1 { <EX2> + % '/' }
在<EX2>
之后加上之前和之间的间距是多余的:
/
答案 1 :(得分:4)
significant中的空格为rule
s。因此,我认为您在最后一个<EX2>
之后缺少空格:
rule EX1 { <EX2> ( '/' <EX2>)+ }
应该是:
rule EX1 { <EX2> ( '/' <EX2> )+ }
这将留出空间来分隔EX1
中的术语。