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

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

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

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

say $0;

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

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

「ab」   # final say

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

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

'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」]

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


person Julio    schedule 09.12.2020    source источник
comment
в вашем втором примере я не понимаю использования квадратных скобок. Если я помещаю квадратные скобки внутри скобок, я получаю тот же результат, что и только скобки, то есть ([\w+]) и ([\w])+ имитируют их неквадратные скобки, содержащие их аналоги.   -  person jubilatious1    schedule 10.12.2020
comment
@ jubilatious1 Да, скобки бесполезны :). Исходное регулярное выражение было более сложным, и я начал удалять его части, чтобы получить простейший случай. Наконец-то забыл снять скобки.   -  person Julio    schedule 10.12.2020


Ответы (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] соответствует символу, который был окончательно сопоставлен в этой итерации.

person Prasanna    schedule 10.12.2020
comment
Даже проще, чем $/.Str.substr(*-1) eq 'b' $/.ends-with: 'b' - person user0721090601; 10.12.2020
comment
Привет! Ваш обходной путь обертывания квантователя дополнительной группой захвата работает как шарм! Посмотрим, что люди ракудо говорят об этом, баг или нет - person Julio; 10.12.2020
comment
@raiph, спасибо - person Prasanna; 11.12.2020
comment
Я не уверен, что понимаю суть проблемы, @Prasanna и @raiph. Если я устраню возврат с помощью наречия :r racheting, я увижу ожидаемый результат. Попробуйте 'abc' ~~ m:r/(\w)+ {say $/;} <?{ False }>/;, спасибо! - person jubilatious1; 11.12.2020
comment
@ jubilatious1, данное регулярное выражение, является упрощенным для демонстрации проблемы. Основываясь на результатах демонстрации, надеюсь, вы согласны с несоответствием. И да, проблема возникает только тогда, когда мы используем отслеживание с возвратом и $0. - person Prasanna; 11.12.2020