#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」]
. Я подозреваю, что это ошибка.
Для вашего случая есть несколько подходов.
- Просто используйте
$/
для проверки состояния'abc' ~~ m/[(w)] <?{ $/.Str.substr(*-1) eq 'b' }>/;
- Или, кроме того, также захватите группу с помощью кватификаторов.
'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
.