使用语法在没有前瞻的情况下解析字符串?

Using a grammar to parse a string without lookahead?

收到此文本:

Want this || Not this

该行也可能如下所示:

Want this | Not this

用一根管子。

我正在使用这个语法来解析它:

    grammar HC {
       token TOP {  <pre> <divider> <post> }
       token pre { \N*? <?before <divider>> }
       token divider { <[|]> ** 1..2 } 
       token post { \N* }
    } 

有更好的方法吗?我希望能够做更多像这样的事情:

    grammar HC {
       token TOP {  <pre> <divider> <post> }
       token pre { \N*? }
       token divider { <[|]> ** 1..2 }
       token post { \N* }
    } 

但这不起作用。如果我这样做:

    grammar HC {
       token TOP {  <pre>* <divider> <post> }
       token pre { \N }
       token divider { <[|]> ** 1..2 } }
       token post { \N* }
    } 

分隔符之前的每个字符都有自己的 <pre> 捕获。谢谢。

一如既往,TIMTOWTDI。

I'd love to be able to do something more like this

可以。只需将前两个规则声明从 token 切换为 regex:

grammar HC {
  regex TOP {  <pre> <divider> <post> }
  regex pre { \N*? }
  token divider { <[|]> ** 1..2 }
  token post { \N* }
} 

这是有效的,因为 regex 禁用了 :ratchet(不像 tokenrule 启用它)。

(解释为什么你需要为 两个 规则关闭它超出了我的薪水等级,当然是今晚,并且很可能直到其他人向我解释为什么我可以假装我一直都知道。)

if I do this ... each character gets its own <pre> capture

默认情况下,"calling a named regex installs a named capture with the same name" [...后面几句:]“如果不需要捕获,前导点或符号将取消它”。所以将 <pre> 更改为 <.pre>.

接下来,您可以 manually add a named capture 通过在 $<name>=[pattern] 中包装一个模式。因此,要捕获 整个字符串 pre 规则的连续调用相匹配,请包装 捕获模式(<.pre>*?) 在 $<pre>=[...]):

grammar HC {
       token TOP { $<pre>=[<.pre>*?] <divider> <post> }
       token pre { \N }
       token divider { <[|]> ** 1..2 }
       token post { \N* }
    } 

好的 - 我尝试了 use Grammar::Tracer;(我们最好的朋友!)并从你的原始答案和第一个使用正则表达式的答案中得到了这个......对我来说都是错误的......

TOP
|  pre
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * FAIL
|  |  divider
|  |  * MATCH "|"
|  * MATCH "Want this "
|  divider
|  * MATCH "|"
|  post
|  * MATCH " Not this"
* MATCH "Want this | Not this"
「Want this | Not this」
 pre => 「Want this 」
 divider => 「|」
 post => 「 Not this」

这让我感觉你的pre和divider的组合没有收敛。所以我把代码改成这样(对 pre 有更明确的定义)...

  1 use Grammar::Tracer;
  2 
  3 grammar HC {
  4        token TOP {  <pre> <divider> <post> }
  5        token pre {  <-[|]>* }
  6        token divider { <[|]> ** 1..2 }
  7        token post { \N* }
  8 }  

得到这个...

TOP
|  pre
|  * MATCH "Want this "
|  divider
|  * MATCH "|"
|  post
|  * MATCH " Not this"
* MATCH "Want this | Not this"
「Want this | Not this」
 pre => 「Want this 」
 divider => 「|」
 post => 「 Not this」

Sooo - 我的结论是 (i) 使用 Grammar::Tracer 检查语法的操作是必须做的,(ii) 像原始定义这样的松散定义要求解析器在每个字符边界上进行测试应该是避免,(iii)特别是如果分频器很难确定

我有更广泛的 感觉 语法(解析器)可能不太适合底层的原始数据结构,并且一组正则表达式可能是更好的方法。

我没弄清楚如何使用 <.ws> 或等效于 trim 捕获结果中的空格。