Perl6解析文件

use*_*164 3 regex grammar perl6

作为练习,我试图解析一些标准文本,它是shell命令的输出.

  pool: thisPool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
    still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
    the pool may no longer be accessible by software that does not support
    the features. See zpool-features(5) for details.
  scan: none requested
config:

    NAME                                                STATE     READ WRITE CKSUM
    homePool                                            ONLINE       0     0     0
      mirror-0                                          ONLINE       0     0     0
        ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7NUE93C      ONLINE       0     0     0
        ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7RE2A4F      ONLINE       0     0     0
    cache
      ata-KINGSTON_SV300S37A60G_50026B7261025D7E-part3  ONLINE       0     0     0

errors: No known data errors
Run Code Online (Sandbox Code Playgroud)

我想使用Perl6语法,我想在单独的令牌或正则表达式中捕获每个字段.所以,我做了以下语法:

grammar zpool {
        regex TOP { \s+ [ <keyword> <collection> ]+ }
        token keyword { "pool: " | "state: " | "status: " | "action: " | "scan: " | "config: " | "errors: " }
        regex collection { [<:!keyword>]*  }
}
Run Code Online (Sandbox Code Playgroud)

我的想法是正则表达式找到一个关键字,然后开始收集所有数据,直到下一个关键字.但是,每次,我只得到"池:" - >所有剩余的文本.

 keyword => ?pool: ?
 collection => ?homePool
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
    still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
    the pool may no longer be accessible by software that does not support
    the features. See zpool-features(5) for details.
  scan: none requested
config:

    NAME                                                STATE     READ WRITE CKSUM
    homePool                                            ONLINE       0     0     0
      mirror-0                                          ONLINE       0     0     0
        ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7NUE93C      ONLINE       0     0     0
        ata-WDC_WD5000AZLX-00CL5A0_WD-WCC3F7RE2A4F      ONLINE       0     0     0
    cache
      ata-KINGSTON_SV300S37A60G_50026B7261025D7E-part3  ONLINE       0     0     0

errors: No known data errors
?
Run Code Online (Sandbox Code Playgroud)

我不知道如何让它在找到关键字时停止吃字符,然后将其视为另一个关键字.

rai*_*iph 5

问题1

你写的<:!keyword>不是<!keyword>.那不是你想要的.你需要删除:.

<:foo>P6正则表达式的语法将单个字符与指定的Unicode属性匹配,在这种情况下,该属性:foo反过来意味着:foo(True).

并将<:!keyword>单个字符与Unicode属性匹配:keyword(False).

但是没有Unicode属性:keyword.

因此,否定断言将始终为真,并且每次始终匹配单个输入字符.

因此,正如您所知,模式只是通过文本的其余部分.

问题2

一旦解决问题1,就会出现第二个问题.

<:!keyword>使用Unicode属性匹配单个字符:keyword(False).每次匹配时,它会自动弹出一些输入(单个字符).

相反,<!keyword>如果匹配则不消耗任何输入.你必须确保使用它的模式能够输入.


解决这两个问题后,您将获得预期的输出.(您将看到的下一个问题是config关键字不起作用,因为输入文件示例:中的config:in后面没有空格.)


所以,有一些清理:

my @keywords = <pool state status action scan config errors> ;

say grammar zpool {
    token TOP        { \s+ [ <keyword> <collection> ]* }
    token keyword    { @keywords ': ' }
    token collection { [ <!keyword> . ]* }
}
Run Code Online (Sandbox Code Playgroud)

我已将所有模式切换为token声明.一般情况下,token除非您知道自己需要其他东西,否则请务必使 (regex启用回溯.如果你不小心的话,这可能会大大降低速度.rule使规则中的空格显着.)

我已将关键字提取到数组中.@keywords手段@keywords[0] | @keywords[1] | ....

我在最后一个模式中添加了一个.after <!keyword>(消耗一个字符的输入值,以避免在<!foo>不消耗任何输入的情况下会发生的无限循环).

如果您还没有看到它们,请注意可用的语法调试选项是您的朋友.

心连心