【问题标题】:Perl6 grammars: match full linePerl6 语法:匹配整行
【发布时间】:2015-12-29 07:01:11
【问题描述】:

我刚刚开始探索 perl6 语法。我怎样才能组成一个标记“行”来匹配行的开头和结尾之间的所有内容?我尝试了以下方法但没有成功:

my $txt = q:to/EOS/;
    row 1
    row 2
    row 3
    EOS


grammar sample {
    token TOP {
        <line>
    }

    token line {
        ^^.*$$
    }
}

my $match = sample.parse($txt);

say $match<line>[0];

【问题讨论】:

    标签: grammar raku


    【解决方案1】:

    我可以在您的语法中看到 2 个问题,这里的第一个是标记行,^^ 和 $$ 是行首和行尾的锚点,但是您可以在两者之间添加新行。为了说明,我们只使用一个简单的正则表达式,先不使用语法:

    my $txt = q:to/EOS/;
        row 1
        row 2
        row 3
        EOS
    
    if $txt ~~ m/^^.*$$/ {
        say "match";
        say $/;
    }
    

    运行,输出为:

    match
    「row 1
    row 2
    row 3」
    

    你看到正则表达式匹配的比期望的要多,但是第一个问题不存在,这是因为棘轮,与令牌匹配将不起作用:

    my $txt = q:to/EOS/;
        row 1
        row 2
        row 3
        EOS
    
    my regex r {^^.*$$};
    if $txt ~~ &r {
        say "match regex";
        say $/;
    } else {
        say "does not match regex";
    }
    my token t {^^.*$$};
    if $txt ~~ &t {
        say "match token";
        say $/;
    } else {
        say "does not match token";
    }
    

    运行,输出为:

    match regex
    「row 1
    row 2
    row 3」
    does not match token
    

    我不太确定为什么,但令牌和锚 $$ 似乎不能很好地协同工作。但是您想要的是搜索除换行符之外的所有内容,即 \N* 以下语法主要解决您的问题:

    grammar sample {
        token TOP {<line>}
        token line {\N+}
    }
    

    但是它只匹配第一次出现,当您只搜索一行时,您可能想要做的是搜索一行 + 一个可选的垂直空格(在您的情况下,您的末尾有一个新行字符串,但我猜你想取最后一行,即使最后没有新行),重复几次:

    my $txt = q:to/EOS/;
        row 1
        row 2
        row 3
        EOS
    
    grammar sample {
        token TOP {[<line>\v?]*}
        token line {\N+}
    }
    
    my $match = sample.parse($txt);
    for $match<line> -> $l {
        say $l;
    }
    

    该脚本的输出开始:

    「row 1」
    「row 2」
    「row 3」
    

    为了帮助您使用和调试 Grammar,还有 2 个非常有用的模块:Grammar::Tracer 和 Grammar::Debugger。只需将它们包含在脚本的开头即可。 Tracer 显示由您的语法完成的匹配的彩色树。调试器可以让你实时看到它的匹配步骤。

    【讨论】:

    • 阅读 Christoph 的评论,我意识到为什么 token 和 $$ 不能正常工作。令牌不进行回溯(因为棘轮),因此在 ^^.*$$ 中 .* 正在捕获行的最后一个结尾并且 $$ 不再匹配。在 chritoph 评论中, .*?使 .* 不贪婪,因此 $$ 可以匹配
    • 还有一点有趣的是%操作符,在一个量词之后,查看如下版本:my $txt = "row 1\nrow 2\nrow 3";语法示例 { token TOP {* % \v} token line {\N+} } my $match = sample.subparse($txt);对于 $match -> $l { 说 $l; }
    【解决方案2】:

    你原来的方法可以通过

    grammar sample {
        token TOP { <line>+ %% \n }
        token line { ^^ .*? $$ }
    }
    

    就我个人而言,我不会尝试锚定 line 并使用 \N 来代替已经建议的。

    【讨论】:

      【解决方案3】:
      my $txt = q:to/EOS/;
      row 1
      row 2
      row 3
      EOS
      
      
      grammar sample {
          token TOP {
              <line>+
          }
          token line {
              \N+ \n
          }
      }
      
      my $match = sample.parse($txt);
      
      say $match<line>[0];
      

      或者,如果您可以具体说明该行:

      grammar sample {
          token TOP {
              <line>+
          }
          rule line {
              \w+ \d
          }
      }
      

      【讨论】:

        【解决方案4】:
        my $txt = q:to/EOS/;
            row 1
            row 2
            row 3
            EOS
        
        grammar sample {
            token TOP { <line> }
            token line { .* }
        }
        
        for $txt.lines -> $line {
            ## An single line of text....
            say $line;
            ## Parse line of text to find match obj...
            my $match = sample.parse($line);
            say $match<line>;
        }
        

        【讨论】:

        • 我觉得这并不能回答最初的问题,因为标记“行”只是匹配你扔给它的任何东西。在这种情况下,它恰好匹配“一条完整的行”,因为这就是你一次给它的全部。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多