Perl 6 Grammar与我认为不应该匹配

时间:2017-12-09 12:11:20

标签: regex grammar perl6

我在做Advent of Code day 9

  

你坐了一会儿并记录了部分流(你的拼图输入)。字符代表组 - 以{开头并以}结尾的序列。在一个组中,有零个或多个其他东西,用逗号分隔:另一个组或垃圾。由于组可以包含其他组,}仅关闭最近打开的未关闭组 - 也就是说,它们是可嵌套的。您的拼图输入代表一个单独的大组,它本身包含许多较小的组。

     

有时候,你会发现垃圾,而不是一群人。垃圾以<开头,以>结尾。在这些尖括号之间,几乎可以出现任何字符,包括{}。在垃圾中,<没有特殊含义。

     

为了清理垃圾是徒劳的,有些程序使用!取消了其中的一些字符:在垃圾内部,!之后的任何字符都应该被忽略,包括{{ 1}},<,甚至是另一个>

当然,这对于Perl 6 Grammar来说是尖叫......

!

这似乎可以在简单的示例中正常工作,但连续两个grammar Stream { rule TOP { ^ <group> $ } rule group { '{' [ <group> || <garbage> ]* % ',' '}' } rule garbage { '<' [ <garbchar> | <garbignore> ]* '>' } token garbignore { '!' . } token garbchar { <-[ !> ]> } } 出错:

garbchar

给出say Stream.parse('{<aa>}');

Nil没有帮助:

Grammar::Tracer

多个TOP | group | | group | | * FAIL | | garbage | | | garbchar | | | * MATCH "a" | | * FAIL | * FAIL * FAIL Nil 没问题:

garbignore

给出:

say Stream.parse('{<!!a!a>}');

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

UPD 鉴于代码问题的出现并未提及空白,您根本不应该使用rule构造。只需将所有rule切换为token,即可进行设置。一般情况下,请遵循Brad的建议 - 使用token,除非您知道您需要rule(下面讨论过)或regex(如果您需要回溯)。

我在下面的原始答案探讨了为什么rule没有用。我现在就把它留下来。

TL; DR <garbchar> |包含空格。直接跟随rule中的任何atom的空格表示标记化中断。你可以简单地删除这个不适当的空间,即改为写<garbchar>|(或者更好的是<.garbchar>|如果你不需要捕获垃圾)来获得你想要的结果。

正如你原来的问题所允许的那样,这不是一个错误,只是你的心智模型已经关闭。

您的回答正确识别了问题:tokenization

所以我们留下的是你的后续问题,这是关于你的标记化的心智模型,或者至少是默认情况下Perl 6如何标记:

  

为什么......我的第二个例子......连续两个服装器出了问题:

'{<aa>}'

简化,问题是如何对此进行标记:

aa

简单的高级答案是,在解析白话时,aa通常会被视为一个标记,而不是两个标记,默认情况下,Perl 6会假定这个普通的定义。这是您遇到的问题。

您可以否决这个普通的定义,以获得您想要达到的任何标记化结果。但是很少有必要这样做,而且在这种简单的情况下肯定不是这样。

我会提供两条冗余路径,希望这些路径能引导民众走向正确的心智模式:

摘自the "Obstacles" section of the wikipedia page on tokenization,并将摘录与P6特定讨论交错:

  

通常,标记化发生在单词级别。但是,有时很难定义&#34; word&#34;的含义。通常,标记生成器依赖于简单的启发式方法,例如:

     
      
  • 标点符号和空格可能包含也可能不包含在生成的令牌列表中。
  •   

在Perl 6中,您可以使用与标记化正交的捕获功能来控制在解析树中包含或不包含的内容。

  
      
  • 所有连续的字母字符串都是一个令牌的一部分;同样有数字。

  •   
  • 标记由空格字符分隔,例如空格或换行符或标点字符。

  •   

默认情况下,Perl 6设计体现了这两种启发式的等价物。

要获得的关键是它是rule构造,它处理一串令牌,复数。 token构造用于定义每次调用的单个令牌

我想我会在这里结束我的答案,因为它已经很久了。请使用评论来帮助我们改进这个答案。我希望到目前为止我所写的内容有所帮助。

答案 1 :(得分:3)

对我自己的问题的部分回答:将所有rule更改为token并且它有效。 这是有道理的,因为差异是:sigspace,我们在这里不需要或想要。但是,我不明白,为什么它对某些输入起作用,就像我的第二个例子一样。

如果您感兴趣,结果代码为here