当前位置: 首页 > 知识库问答 >
问题:

Perl6解析文件

习阳
2023-03-14

作为实践,我正在尝试解析一些作为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

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

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

我的想法是,正则表达式找到一个关键字,然后开始收集所有数据,直到下一个关键字。然而,每次我都会得到“池”:-

 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
」

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

共有2个答案

呼延修然
2023-03-14
匿名用户

尽管我不时地喜欢好的语法,但通过调用split可以更容易地解决这个问题:

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;

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

现在,由于您要求语法,我们可以通过将每个值替换为.?(任何字符串,但尽可能短)来轻松地将拆分调用转换为纯正则表达式。

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

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>+              }
}

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

class ZPool::Actions {
    has $!last-key;
    has %.contents;
    method key($m)   { $!last-key = $m.Str                }
    method value($m) { %!contents{ $!last-key } = $m.trim }
}

然后使用它:

my $actions = ZPool::Actions.new;
ZPool.parse($input, :$actions);
say $actions.contents.perl;

< code>key和< code>keychunk不需要回溯,所以可以将它们从< code>regex改为< code>token。

当然,使用. ? 和回溯可能被认为是作弊,因此您可以使用raiph提到的技巧,在value正则表达式中带有负面展望。

姜锋
2023-03-14

问题1

您已经编写了<代码>

和<code>

但是没有Unicode属性:关键字

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

所以,正如你所知道的,这个模式只是通过文本的其余部分来咀嚼。

问题2

修复问题 1 后,会出现第二个问题。

<代码>

相比之下,< code >

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

所以,通过一些清理:

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

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

我已将所有模式转换为令牌声明。通常,除非您知道自己需要其他东西,否则请始终使用令牌。(正则表达式支持回溯。如果你不小心,这可能会大大减慢速度。规则使规则中的空格变得重要。

我已经将关键字提取到一个数组中。@关键字表示@关键字[0]|@关键字[1]|…

我添加了一个<code> 之后

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

呵呵

 类似资料:
  • 在Perl 5中,我能够多次设置一个选项,就像在这个问题中一样: 多次使用相同选项的Perl Getopt 我想知道是否有可能对Perl 6和MAIN子级做同样的事情?

  • 我正在尝试创建一个语法。到目前为止,这是我的代码: 我真的只是希望语法从输入中创建一个列表/哈希表树。代码的输出是: 看起来还不错。perl6似乎在解码这样一个事实,即字段描述符由多个字段描述符组成,但实际上似乎并没有将它们放入列表中。我可以说$fds ,但我不能说$fds[0] 。为什么前者“起作用”,而后者不起作用? 我必须承认,我对正在发生的事情掌握得相当薄弱。使用规则而不是令牌会更好吗?我

  • 译注: 在原文标题后加上小括号以表示其为方法名,以与一般标题加以区别。 exit() 在学习怎么处理文件之前,我们先来了解一些实用的函数。 exit()能够使程序在任何调用它的地方退出,即无需运行到最后一行就结束。 tutorial/files/exit.p6 #!/usr/bin/env perl6 use v6; say "hello"; exit; say "world"; warn

  • 这是我第一次使用YAML文件,所以我首先想到的是找到任何可以帮助我解析文件的库。 我找到了两个库,YamlBean和snakeyaml。我不确定我要用哪一个。 下面是我试图解析的文件的一个示例: 该文件将动态更改,所以我不知道该文件将包含多少用户或组。 有人能帮我开始吗?最好的图书馆是什么?YamlBean还是Snakeyaml? 我想,我需要将这些信息保存在一个可以轻松重复的东西中。

  • 详细内容请看这里

  • 我正在玩基于Windows上的MoarVM构建的perl6版本。我创建了一些perl6文件并想将其编译为exe。我尝试了以下操作: 现在我想把r编译成可执行文件 我发现这个链接谈论如何使用鹦鹉,但我正在使用MoarVM目标:http://perlgeek.de/blog-en/perl-6/my-first-executable.writeback 我的问题如何将MoarvVM目标文件编译为Win