Грамматические регулярные выражения сопоставляются независимо, но не вместе - PullRequest
3 голосов
/ 11 октября 2019

Это моя попытка решить еженедельную задачу «реализовать расширение скобок». Я написал ниже грамматику, которая должна работать. Но не.

grammar BraceExpansion
{
    regex TOP          { <start-txt> <to-expand> <end-txt> }
    regex start-txt    { <save-char>* }
    regex end-txt      { <save-char>* }
    token save-char    { <-[ \" \& \( \) \` \' \; \< \> \| ]> }
    token list-element { <-[ \" \! \$ \& \( \) \` \' \; \< \> \| ]> }
    token alphanum     { <[ a..z A..Z 0..9 ]> }
    token alpha        { <[ a..z A..Z ]> }
    regex num          { \-? <[ 0..9 ]>+ }
    regex to-expand    { <range> | <list>  }
    regex range        { <alpha-range> | <num-range> }
    regex num-range    { \{ <num>  \. \. <num> [ \. \. <num> ]? \} }
    regex alpha-range  { \{ <alpha> \. \. <alpha> [ \. \.<num> ]? \} }
    regex list         { \{ <list-element>+ % ',' \} }
}

say brace-expand( 'A{1..3}B{a..g..3}C{1,2}D' );

sub num-range( $match )
{
    say "-NUM-";
    my @num = |$match<range><num-range><num>.list>>.Int;
    my @range = @num[0] ... @num[1];
    my $steps = ( @num[2] // 1 ).abs;
    @range.batch( $steps )>>.[0];
}


sub alpha-range( $match )
{
    say "-ALPHA-";
    my @num = |$match<range><alpha-range><alpha>.list>>.Str;
    my @range = @num[0] ... @num[1];
    my $steps = ( $match<range><alpha-range><num> // 1 ).abs;
    @range.batch($steps)>>.[0];
}

sub list( $match )
{
    say "-LIST-";
    $match<list><list-element>.list>>.Str;
}

sub brace-expand( $str )
{
    say "brace-expand( $str )";

    my $match = BraceExpansion.parse( $str );

    my @alternatives =
        $match<range><num-range>   ?? num-range( $match )   !!
        $match<range><alpha-range> ?? alpha-range( $match ) !!
        $match<list>               ?? list( $match )        !!
        ();

    say "A", @alternatives;

    return $str
        unless @alternatives;

    @alternatives
         .map( -> $element { $match<start-txt>.Str ~ $element ~ $match<end-txt>.Str } )
         .map( -> $result  { brace-expand( $result ) } )
    ;
}

Однако, если я изменю правило TOP на

    regex TOP          { <start-txt> <range> <end-txt> }

или

    regex TOP          { <start-txt> <list> <end-txt> }

range и list токены работают независимо, и я получаю ожидаемый результат. Но когда я использую правило to-expand, вся грамматика не совпадает, и я не могу понять, почему. Это изменение не так? Но если так, то почему тогда <alpha-range> | <num-range> работает?

.... (проходит время) ....

Тем временем я узнал, что

regex TOP           { <start-txt> [ <range> | <list> ] <end-txt> } 

делает то, что я хочу. Но мой вопрос остается в силе, почему он не работает, как указано выше?

1 Ответ

2 голосов
/ 04 ноября 2019

Матч происходит нормально;Вы не вписываетесь в матч правильно. Структура получающегося соответствия:

start-txt => 「A{1..3}B{a..g..3}C」
  save-char => 「A」
  ...
to-expand => 「{1,2}」
  list => 「{1,2}」  # (or range)
  ...
end-txt => 「D」
  save-char => 「D」
  ...

Но вы индексируете это как $match<list>. Сначала вы должны индексировать в <to-expand> как $match<to-expand><list>. Попробуйте онлайн!

Причина, по которой модифицированная версия работает, заключается в том, что вы удаляете этот промежуточный шаг to-expand, чтобы индекс работал.

...