Почему я получаю разные обратные отслеживания с этими регулярными выражениями Raku?

#regex #raku #quantifiers #rakudo

#регулярное выражение #raku #кванторы #ракудо

Вопрос:

Я получаю неожиданное обратное отслеживание квантора регулярного выражения Raku.

В этом регулярном выражении:

 'abc' ~~ m/(w ) {say $0}  <?{ $0.substr(*-1) eq 'b' }>/;

say $0;
 

Я получаю ожидаемый результат:

 「abc」  # inner say
「ab」   # inner say

「ab」   # final say
 

То есть (жадный) квантификатор получает все буквы, а затем условие завершается ошибкой. После этого он начинает откат, освобождая последнюю полученную букву, пока условное значение не примет значение true.

Однако обратное отслеживание, похоже, не работает одинаково, когда я помещаю квантификатор вне группы захвата:

 'abc' ~~ m/[(w)]  {say $0}  <?{ $0.tail eq 'b' }>/;

say $0;
 

Результат:

 [「a」 「b」 「c]  # inner say
[「a」 「b」 「c]  # why this extra inner say? Shouldn't this backtrack to [「a」 「b」]?
[「a」 「b」 「c]  # why this extra inner say? Shouldn't this backtrack to [「a」 「b」]?
[「b」 「c]      # Since we could not successfully backtrack, We go on matching by increasing the position
[「b」 「c]      # Previous conditional fails. We get this extra inner say
[c]          # Since we could not successfully backtrack, We go on matching by increasing the position

Nil            # final say, no match because we could not find a final 'b'
 

Ожидается ли такое поведение? Если да: почему они работают по-разному? Можно ли имитировать первое регулярное выражение, но при этом сохранить квантификатор вне группы захвата?

ПРИМЕЧАНИЕ:

Использование ленивого квантификатора «решает» проблему… Это ожидаемо, потому что разница, похоже, возникает при обратном отслеживании, а этого не происходит с ленивым квантификатором.

 'abc' ~~ m/[(w)] ? {say $0}  <?{ $0.tail eq 'b' }>/;

[「a」]
[「a」 「b」]

[「a」 「b」]
 

Однако по соображениям производительности я бы предпочел использовать жадный квантификатор (пример в этом вопросе является упрощением).

Комментарии:

1. в вашем втором примере я не понимаю использования квадратных скобок. Если я помещаю квадратные скобки внутри круглых скобок, я получаю тот же результат, что и только круглые скобки, т. Е. ([w ]) ([w]) Имитирую их аналоги, не содержащие квадратные скобки.

2. @jubilatious1 Да, скобки бесполезны :). Исходное регулярное выражение было более сложным, и я начал удалять его части, чтобы получить простейший случай. Я, наконец, забыл убрать скобки.

Ответ №1:

Я не думаю, что проблема в обратном отслеживании. Но, похоже, что промежуточное $0 раскрытие сохранило записи предыдущей итерации. Рассмотрим это выражение,

 'abc' ~~ m/[(w)]  {say "Match:",$/.Str,";tCapture:",$0}  <?{ False }>/;
 

Это результат:

 Match:abc;  Capture:[「a」 「b」 「c]
Match:ab;   Capture:[「a」 「b」 「c]
Match:a;    Capture:[「a」 「b」 「c]
Match:bc;   Capture:[「b」 「c]
Match:b;    Capture:[「b」 「c]
Match:c;    Capture:[c]
 

Как вы можете видеть, совпадение в правильном порядке, abc ab a ... . Но захваченный массив для ab сопоставления также [「a」 「b」 「c」] . Я подозреваю, что это ошибка.


Для вашего случая есть несколько подходов.

  1. Просто используйте $/ для проверки состояния
     'abc' ~~ m/[(w)]   <?{ $/.Str.substr(*-1) eq 'b' }>/;
     
  2. Или, кроме того, также захватите группу с помощью кватификаторов.
     'abc' ~~ m/([(w)] ) <?{ $0[0][*-1] eq 'b' }>/;
     

    Здесь $0 соответствует внешней группе, $0[0] соответствует первой внутренней группе, $[0][*-1] соответствует символу, который был окончательно сопоставлен на этой итерации.


Комментарии:

1. Даже проще, чем $/.Str.substr(*-1) eq 'b' есть $/.ends-with: 'b'

2. Привет! Ваш обходной путь обертывания квантователя дополнительной группой захвата работает как шарм! Давайте посмотрим, что люди из rakudo говорят об этом, ошибка это или нет

3. Я зарегистрировал проблему с (foo) соответствующими вложенными записями, которые не удаляются во время обратного отслеживания .

4. @raiph, спасибо

5. @jubilatious1, приведенное регулярное выражение, является упрощенным для демонстрации проблемы. Основываясь на выводе демо, надеюсь, вы согласны с тем, что есть несоответствие. И да, проблема возникает только тогда, когда мы используем обратное отслеживание и $0 .