提问者:小点点

如何在Raku中使用匹配的分隔符


我正在尝试编写一个令牌,允许带有匹配分隔符的嵌套内容。如果不是“(AB)”,其中(AB)应该导致至少匹配“AB”。并且(A(c)B)将返回两个匹配项“(A(c)B)”等等。

代码从其来源归结为:

#!/home/hsmyers/rakudo741/bin/perl6
use v6d;

my @tie;

class add-in {
    method tie($/) { @tie.push: $/; }
}

grammar tied {
    rule TOP { <line>* }
    token line {
        <.ws>?
        [
            | <tie>
            | <simpleNotes>
        ]+
        <.ws>?
    }
    token tie {
        [
            || <.ws>? <simpleNotes>+ <tie>* <simpleNotes>* <.ws>?
            || <openParen> ~ <closeParen> <tie>
        ]+
    }
    token openParen { '(' }
    token closeParen { ')' }
    token simpleNotes {
        [
            | <[A..Ga..g,'>0..9]>
            | <[|\]]>
            | <blank>
        ]
    }
}

my $text = "(c2D) | (aA) (A2 | B)>G A>F G>E (A,2 |\nD)>F A>c d>f |]";

tied.parse($text, actions => add-in.new).say;
$text.say;
for (@tie) {
    s:g/\v/\\n/;
    say "«$_»";
}

这给出了部分正确的结果:

«c2D»
«aA»
«(aA)»
«A2 | B»
«\nD»
«A,2 |\nD»
«(A,2 |\nD)>F A>c d>f |]»
«(c2D) | (aA) (A2 | B)>G A>F G>E (A,2 |\nD)>F A>c d>f |]»

BTW,我不关心换行符,它只是检查这种方法是否可以跨越两行文本。所以搅拌我看到的灰烬会捕获带括号和不带括号的内容,以及一两个非常贪婪的捕获。

很明显,我的代码中有一个问题。我对perl6的了解最好被描述为“初学者”,所以我请求你的帮助。我正在寻找一个通用的解决方案,或者至少是一个可以概括的例子,一如既往地欢迎建议和更正。


共1个答案

匿名用户

您还有一些额外的复杂性。例如,您将领带定义为(…)或只是。但是内部内容与该行相同。

这里有一个重写的语法,大大简化了你想要的东西。编写语法时,从小处着手,往上走是有帮助的。

grammar Tied {
    rule  TOP   { <notes>+ %% \v+ }
    token notes {
        [
        | <tie>
        | <simple-note>
        ] + 
        %%
        <.ws>?
    }
    token open-tie    { '(' }
    token close-tie   { ')' }
    token tie         { <.open-tie> ~ <.close-tie> <notes> }
    token simple-note { <[A..Ga..g,'>0..9|\]]>             }
}

这里有一些文体上的注释。语法是类,通常将它们大写。标记是方法,带有kebap大小写(不过,您当然可以使用任何您想要的类型)。在tie标记中,您会注意到我使用了

现在,我创建代币的顺序是这样的:

动作(通常与你的语法同名,加上-Action,所以这里我使用类Teded-Actions{

  1. 我们想从TOP中得到什么?
    在我们的例子中,我们只想要我们在每个中找到的所有联系

解析时,您需要做的就是获取Match. make

say Tied.parse("a(b(c))d");
# 「a(b(c))d」
# notes => 「a(b(c))d」
#  simple-note => 「a」
#  tie => 「(b(c))」          <-- there's a tie!
#   notes => 「b(c)」
#    simple-note => 「b」
#    tie => 「(c)」           <-- there's another!
#     notes => 「c」
#      simple-note => 「c」
#  simple-note => 「d」
say Tied.parse("a(b(c))d", actions => TiedActions).made;
# [b(c) c]

现在,如果你真的只需要领带

class Tied-Actions {
    has @!ties;
    method TOP ($/) { make @!ties            }
    method tie ($/) { @!ties.push: ~$<notes> }
}

与之前相比,这有几个缺点:虽然它可以工作,但它的可扩展性不是很好。虽然你会得到每一个平局,但你对它的上下文一无所知。此外,你必须实例化Ted-Action(即action=