语法未按预期解析并带有否定环视断言

Ste*_*ieD 5 grammar raku

好吧,这要么是一个错误,要么我看起来像个十足的白痴,而且我使用的环视断言完全错误。我不关心后者,所以我们开始吧。

我正在测试这个语法:

our grammar HC2 {
        token TOP { <line>+ }
        token line { [ <header> \n | <not-header> \n ] }
        token header { <header-start> <header-content> }
        token not-header { \N* }
        token header-start { <header-one> }
        token header-one { <[#]> <![#]> } # note this negative lookahead here
        token header-content { \N* }
}
Run Code Online (Sandbox Code Playgroud)

我想捕获一个只有一个#符号的 Markdown 标题,仅此而已。

这是 Grammar::Tracer/Debugger 的输出:

在此输入图像描述

所以它会直接跳过<header-start>捕获。如果我删除<![#]>否定的前瞻断言,我会得到以下结果:

在此输入图像描述

这是一个错误还是我出去吃午饭了?

作为文本:

TOP
> 
|  line
> 
|  |  not-header
> 
|  |  * MATCH "# Grandmother's for a Brighter Future"
> 
|  * MATCH "# Grandmother's for a Brighter Future\n"
> 
|  line
> 
|  |  not-header
> 
|  |  * MATCH ""
> 
|  * MATCH "\n"
> 
|  line
> 
|  |  not-header
> 
|  |  * MATCH "# Development site"
> 
|  * MATCH "# Development site\n"
> 
|  line
> 
|  |  not-header
> 
|  |  * MATCH "* The new site is up and running at example.com"
> 
|  * MATCH "* The new site is up and running at example.com\n"
> 
|  line
> 
|  |  not-header
> 


TOP
> 
|  line
> 
|  |  header
> 
|  |  |  header-start
> 
|  |  |  |  header-one
> 
|  |  |  |  * MATCH "#"
> 
|  |  |  * MATCH "#"
> 
|  |  |  header-content
> 
|  |  |  * MATCH " Grandmother's for a Brighter Future"
> 
|  |  * MATCH "# Grandmother's for a Brighter Future"
> 
|  * MATCH "# Grandmother's for a Brighter Future\n"
> 
|  line
> 
|  |  not-header
> 
|  |  * MATCH ""
> 
|  * MATCH "\n"
> 
|  line
> 
|  |  header
> 
|  |  |  header-start
> 
|  |  |  |  header-one
> 
|  |  |  |  * MATCH "#"
> 
|  |  |  * MATCH "#"
Run Code Online (Sandbox Code Playgroud)

更新:如果我修改header-start为:

token header-one { <[#]> <-[#]> }

它符合预期。然而,这并没有回答为什么原始代码不匹配的问题。

Ste*_*ieD 5

好的,所以非技术性的答案是我做了一个错误的假设,即|角色的行为与 Perl 中的行为相同。它不是。在 Perl 中,正则表达式引擎尝试匹配字符左侧的模式|。如果失败,它将继续执行右侧的模式。

要获得“老式”Perl 行为,请使用||称为“Alternation”运算符的运算符:https://docs.raku.org/language/regexes#Alternation:_||

|运算符称为“最长交替”运算符。请参阅https://docs.raku.org/language/regexes#Longest_alternation:_|

关于“最长交替”运算符如何工作的更详细、更技术性的讨论如下: https: //design.raku.org/S05.html#Longest-token_matching

尽管我已经||通过阅读文档意识到了它的存在,但我并没有仔细阅读它。我错误地认为 Raku 核心开发人员的行为会|像 Perl 中那样,这||是我稍后可以了解的一些很酷的新操作符。

大要点:努力揭示您所做的基本假设,并且在仔细阅读文档之前不要做出任何假设。

  • 看来 Perl 和 Raku 之间的区别应该在这里注意:https://docs.raku.org/language/5to6-perlop (2认同)
  • 该行为被埋在这个长长的“陷阱”页面中:https://docs.raku.org/language/traps#|_vs_||:_which_branch_will_win (2认同)