【问题标题】:How to make Perl 6 grammar produce more than one match (like :ex and :ov)?如何使 Perl 6 语法产生多个匹配项(例如 :ex 和 :ov)?
【发布时间】:2017-10-23 20:24:18
【问题描述】:

我想让grammar 做这样的事情:

> "abc" ~~ m:ex/^ (\w ** 1..2) (\w ** 1..2) $ {say $0, $1}/
「ab」「c」
「a」「bc」

或者像这样:

> my regex left { \S ** 1..2  }
> my regex right { \S ** 1..2  }
> "abc" ~~ m:ex/^ <left><right> $ {say $<left>, $<right>}/
「ab」「c」
「a」「bc」

这是我的grammar

grammar LR {
  regex TOP {
    <left> 
    <right>
  }
  regex left {
    \w ** 1..2 
  }
  regex right {
    \w ** 1..2 
  }
}

my $string = "abc";
my $match = LR.parse($string);
say "input: $string";
printf "split: %s|%s\n", ~$match<left>, ~$match<right>;

它的输出是:

$ input: abc
$ split: ab|c

所以,&lt;left&gt; 只能是贪婪,没有给&lt;right&gt;。我应该如何修改代码以匹配两种可能的变体?

$ input: abc
$ split: a|bc, ab|c

【问题讨论】:

    标签: raku


    【解决方案1】:

    由于Grammar.parse 只返回一个Match 对象,您必须使用不同的方法来获取所有匹配项:

    sub callback($match) {
        say $match;
    }
    grammar LR {
        regex TOP {
            <left> 
            <right>
            $
            { callback($/) }
            # make the match fail, thus forcing backtracking:
            <!>
        }
        regex left {
            \w ** 1..2 
        }
        regex right {
            \w ** 1..2 
        }
    }
    
    LR.parse('abc');
    

    通过调用&lt;!&gt; 断言(总是失败)使匹配失败会强制先前的原子回溯,从而找到不同的解决方案。当然,这会降低语法的可重用性,因为它在语法的常规调用约定之外工作。

    请注意,对于调用者来说,LR.parse 似乎总是失败;您将所有匹配项作为对回调函数的调用。

    一个稍微好一点的 API(但下面的方法相同)是使用 gather/take 来获取所有匹配的序列:

    grammar LR {
        regex TOP {
            <left> 
            <right>
            $
            { take $/ }
            # make the match fail, thus forcing backtracking:
            <!>
        }
        regex left {
            \w ** 1..2 
        }
        regex right {
            \w ** 1..2 
        }
    }
    
    .say for gather LR.parse('abc');
    

    【讨论】:

    • 我从来没有想过使用gathertakeregexes 里面的代码,多么美妙的方法!感谢您的完整回答,它在很多方面对我非常有用!
    【解决方案2】:

    我认为 Moritz Lenz,昵称 moritz,即将出版的新书 "Parsing with Perl 6 Regexes and Grammars" 的作者,是要问这个问题的人。我可能应该让他回答这个问题...

    注意事项

    如果有人考虑尝试修改 grammar.parse 以使其支持 :exhaustive,或以其他方式破解事物以执行 @evb 想要的操作,以下文档可能有用的灵感/指导是我从探索相关推测文档中收集的( S05) 并搜索 #perl6 和 #perl6-dev irc 日志。

    7 年前 Moritz 添加了an edit of S05

    仅影响调用行为而不影响正则表达式本身的 [regex] 修饰符 [例如 :exhaustive] 可能只出现在涉及调用的构造上(如 m// [或 grammar.parse]),而不是在rx// [或regex { ... }]。

    ([例如:exhaustive]、[或grammar.parse]和[或regex { ... }]位是我在这个SO答案中添加的推断/解释/推测。它们不在链接源中.)

    5 年前 Moritz expressed interest in implementing :exhaustive 用于匹配(而非解析)特征。不到 2 分钟后,jnthn 展示了一个单班轮,演示了他猜测他会如何接近它。不到 30 分钟后,莫里茨发布了a working prototypefinal version landed 7 days later

    1 年前 Moritz 在 #perl6 上说(强调由我添加):"regexes and grammars aren't a good tool to find all possible ways to parse a string"

    Hth.

    【讨论】:

    • 谢谢你的回答,我是:ex!我想知道,如果 regexesgrammars 不是一个很好的解析工具……那是什么?
    • 你知道吗,有没有可能获得/购买已经完成的莫里茨书的部分?
    • @EugeneBarsky “那是什么?” - 对?!?我会让莫里茨解释他的意思。首先,引用现在链接回引用的来源,使其在原始上下文中单击即可阅读。也许这会有所帮助。其次,我要去请莫里茨来这里。 Hth.
    • 你必须在上下文中阅读我的报价;有人询问导致歧义解析树的输入;例如,在自然语言处理中很常见的东西。在这种情况下,尝试使用正则表达式/语法来获取所有组合会导致解析树呈指数级增长,因此整个方法存在缺陷。在这种情况下使用正则表达式/语法进行标记化,并建立某种统计模型等等。不要指望正则表达式是神奇的:-)
    • Re my book,没有预览版,但计划于 2017 年 11 月或 12 月出版,因此您不必等待很长时间。它可以预购:amzn.to/2y4EQWG,如果您想在它发布时收到通知,请在perl6book.com 注册邮件列表或在推特上关注@perl6org
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-07
    相关资源
    最近更新 更多