首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Perl6解析文件

Perl6解析文件
EN

Stack Overflow用户
提问于 2017-12-01 22:28:49
回答 2查看 219关注 0票数 3

实际上,我试图解析一些标准文本,这是shell命令的输出。

代码语言:javascript
运行
复制
  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

我希望使用Perl6语法,并希望在单独的令牌或正则表达式中捕获每个字段。因此,我做了以下语法:

代码语言:javascript
运行
复制
grammar zpool {
        regex TOP { \s+ [ <keyword> <collection> ]+ }
        token keyword { "pool: " | "state: " | "status: " | "action: " | "scan: " | "config: " | "errors: " }
        regex collection { [<:!keyword>]*  }
}

我的想法是regex找到一个关键字,然后开始收集所有的数据直到下一个关键字。然而,每次我只得到“池:”->所有剩余的文本。

代码语言:javascript
运行
复制
 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
」

我不知道如何让它停止吃字符时,它找到一个关键字,然后把它作为另一个关键字。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-02 06:45:33

问题1

您已经编写了<:!keyword>而不是<!keyword>。这不是你想要的。您需要删除:

<:foo>语法在P6 regex 将单个字符与指定的Unicode属性匹配。中,在本例中是属性:foo,这反过来意味着:foo(True)

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

但是没有Unicode属性:keyword

因此,否定断言总是正确的,每次都会匹配一个输入字符。

因此,正如你所知道的那样,模式只是在文本的其余部分中咀嚼着自己的方式。

问题2

一旦修复了问题1,就会出现第二个问题。

<:!keyword>将单个字符与Unicode属性:keyword(False)匹配。每次匹配时,它都会自动咀嚼一些输入(一个字符)。

相反,如果<!keyword>匹配,则不会使用任何输入。您必须确保使用它的模式会咀嚼输入。

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

所以,通过一些清理:

代码语言:javascript
运行
复制
my @keywords = <pool state status action scan config errors> ;

say grammar zpool {
    token TOP        { \s+ [ <keyword> <collection> ]* }
    token keyword    { @keywords ': ' }
    token collection { [ <!keyword> . ]* }
}

我已经将所有模式转换为token声明。通常,除非您知道需要其他的东西,否则始终使用token。(regex支持回溯。如果你不小心的话,这会大大减缓事情的发展。rule使规则中的空格非常重要。)

我已经将关键字提取到数组中了。@keywords的意思是@keywords[0] | @keywords[1] | ...

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

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

Hth

票数 6
EN

Stack Overflow用户

发布于 2017-12-02 21:16:46

虽然我有时喜欢一个好的语法,但是通过调用拆分来解决这个问题要容易得多。

代码语言:javascript
运行
复制
my $input = q:to/EOF/;
  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
EOF

my @delimiter = <pool state status action scan config errors>;
my %fields;
for $input.split( / ^^ \h* (@delimiter) ':' \h*/, :v)[1..*] -> $key, $value {
    %fields{ $key[0] } = $value.trim;
}

say %fields.perl;

这是通过对已知的键进行拆分,丢弃第一个元素(因为我们知道输入以键而不是值开始),然后在锁步中迭代键和值。

现在,既然您要求语法,我们可以很容易地将split调用转换为纯正则表达式,方法是将每个值替换为.+? (任何字符串,但尽可能短)。

现在,让我们给它更多的结构:

代码语言:javascript
运行
复制
my @delimiter = <pool state status action scan config errors>;
grammar ZPool {
    regex key      { @delimiter             }
    regex keychunk { ^^ \h* <key> ':'       }
    regex value    { .*?                    }
    regex chunks   { <keychunk> \h* <value> }
    regex TOP      { <chunks>+              }
}

我们可以从嵌套的匹配树中提取结果,或者使用有状态的action对象进行欺骗:

代码语言:javascript
运行
复制
class ZPool::Actions {
    has $!last-key;
    has %.contents;
    method key($m)   { $!last-key = $m.Str                }
    method value($m) { %!contents{ $!last-key } = $m.trim }
}

然后用它:

代码语言:javascript
运行
复制
my $actions = ZPool::Actions.new;
ZPool.parse($input, :$actions);
say $actions.contents.perl;

keykeychunk不需要回溯,所以您可以将它们从regex更改为token

当然,使用.+?和回溯可以被认为是欺骗,所以您可以使用raiph提到的技巧,在value正则表达式中进行负面展望。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47602397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档