Regex Raku正则表达式:最长令牌匹配不一致

Regex Raku正则表达式:最长令牌匹配不一致,regex,raku,rakudo,regex-alternation,Regex,Raku,Rakudo,Regex Alternation,Raku的正则表达式预计将匹配最长的令牌 事实上,这种行为在本规范中有所体现: raku -e "'AA' ~~ m/A {say 1}|AA {say 2}/" # 2 但是,当文本位于变量中时,其工作方式似乎不同: raku -e "my $a = 'A'; my $b = 'AA'; 'AA' ~~ m/$a {say 1}|$b {say 2}/" # 1 为什么它们以不同的方式工作?有没有一种方法可以使用变量并仍然匹配最长的标记?这里有两件事

Raku的正则表达式预计将匹配最长的令牌

事实上,这种行为在本规范中有所体现:

raku -e "'AA' ~~ m/A {say 1}|AA {say 2}/"
# 2
但是,当文本位于变量中时,其工作方式似乎不同:

raku -e "my $a = 'A'; my $b = 'AA'; 'AA' ~~ m/$a {say 1}|$b {say 2}/"
# 1

为什么它们以不同的方式工作?有没有一种方法可以使用变量并仍然匹配最长的标记?

这里有两件事在起作用

第一个是“最长标记”的含义。当存在替代时(使用
|
或通过使用
proto
正则表达式暗示),将提取每个分支的声明性前缀。声明性是指Raku正则表达式语言的子集,可由。声明性前缀是通过使用正则表达式元素来确定的,直到遇到非声明性元素为止。你可以

要理解为什么事情会这样,走一小段弯路可能会有帮助。构建解析器的一种常见方法是编写一个标记器,将输入文本分解为一系列“标记”,然后编写一个解析器,从这些标记中识别更大的(可能是递归的)结构。标记化通常使用有限状态机执行,因为它能够快速减少搜索空间。对于Raku语法,我们不自己编写标记器;相反,它是为我们自动从语法中提取的(更准确地说,每个交替点计算一个标记器)


其次,Raku正则表达式是主Raku语言中的一种嵌套语言,它在一次传递中解析并同时编译。(这与大多数语言不同,在大多数语言中,正则表达式是作为我们传递字符串的库提供的。)最长的令牌计算在编译时进行。但是,变量是在运行时插值的。因此,正则表达式中的变量插值是非声明性的,因此不被视为最长标记匹配的一部分。

此外,Raku表达性的本质意味着定义以完整正则表达式为参数的正则表达式标记
最长
(或
最短
)相当容易。(也就是说,它不一定会被优化,因为至少这种幼稚的方法需要完全遵循每一个匹配),但事实上,你可以做到这一点是非常酷的)。还有,当我去做那个模块时,brb。所以Raku做“文本顺序”匹配,而不是“最长标记”匹配,在RHS上涉及变量?用四个正则表达式
/$A{say 1}|$b{say 2}/
/$A{say 1}|{b{say 2}/
/$b{say 2}|{A{say 1}/
/$b{say 2}say 1}/
进行的快速测试表明这是正确的。@jubilatio1。我认为这里的关键是Jonathan所说的:
声明性前缀是通过使用regex元素**确定的,直到**遇到一个非声明性元素
,例如,这两个匹配是不同的,因为变量的位置:
'AAAA'~~m/$aaa{say 1}|$baa{say 2}/
说1(没有标记被处理,所以它表现为文本顺序)。而
'AAAA'~~m/A$A{say 1}| AA$b{say 2}/
表示2,因为
A
AA
标记被处理,所以它选择了第二次修改,也就是说,如果最长的声明性前缀相等(可能为零),则使用源顺序作为一个连接断路器长度,如果最长的文本连接断路器也不能解决问题(它不能在零长度前缀上解决)。