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 正则表达式语言的子集。声明性前缀是通过采用正则表达式元素来确定的,直到遇到非声明性元素。您可以阅读更多内容并在 docs 中找到更多参考资料。
要理解为什么会这样,绕个小弯可能会有所帮助。构建解析器的一种常用方法是编写一个标记器,它将输入文本分解为一系列“标记”,然后一个解析器从这些标记中识别更大的(可能是递归的)结构。标记化通常使用有限状态机执行,因为它能够快速减少搜索空间。使用 Raku 语法,我们不用自己编写分词器;相反,它会自动为我们从语法中提取(更准确地说,每个交替点都会计算一个分词器)。
其次,Raku 正则表达式是主要 Raku 语言中的一种嵌套语言,使用它一次性解析并同时编译。(这与大多数语言不同,其中正则表达式作为我们将字符串传递给的库提供。)最长的标记计算发生在编译时。但是,变量是在运行时内插的。因此,正则表达式中的变量插值是非声明性的,因此不被视为最长标记匹配的一部分。