Kleene Star: почему $_ = "a"; s/a */e/g производят: ee
a*
означает ноль или более экземпляров: right?
поэтому почему $_ = "a"; s/a*/e/g
производит: ee
Возможный ответ: он заменяет строку: "a": "e" и заменяет пустую строку: "": "e". Или он заменяет простое отсутствие буквы: a буквой: e или заменяет "нулевые вхождения": a с: e
Хорошо, но:
$_ = "b"; s/a*/e/g
производит: ebe
Кажется, он заменяет пустую строку слева от b
, а также пустую строку справа: b
OK. Но почему он не делает этого для: "a
"? Почему он не заменяет пустую строку слева от a
, а также пустую строку справа от нее: a, а также букву: a для получения: eee
?
Существует столько же нулевых вхождений: a с левой стороны как правая сторона!
Ответы
Ответ 1
Ваш анализ того, почему результаты "ee"
и "ebe"
является полностью точным.
Модификатор "/g" заставляет регулярное выражение совпадать один раз, а затем попытаться снова совместить с тем, где остановилось последнее совпадение.
Причина несоответствия (он не заменяет пустую строку слева от "a"
), потому что "*"
жадный - он соответствует MOST возможным символам. Из perldoc perlre
:
По умолчанию квантованный подшаблон является "жадным", то есть он будет соответствовать столько раз, сколько возможно (учитывая конкретное начальное местоположение), сохраняя при этом остальную часть шаблона.
Таким образом, он соответствует нулю "а" и видит, может ли он соответствовать больше. Поскольку в строке больше "а", это будет соответствовать еще одному. Попытайтесь найти больше. Никто? Готово. Таким образом, мы сопоставляем первый "a".
Затем "/g" заставляет нас попытаться снова сопоставить (начиная с того места, где мы остановились после завершения последнего совпадения), который теперь совпадает с пустой строкой (ноль "a" ).
Ответ 2
Используя Damian Conway отличный Regexp:: Debugger, я пробовал это:
perl -MRegexp::Debugger -E '$_ = "a"; s/a*/e/g; say'
И получил этот вывод, если он делает все более ясным, показано в режиме регистрации событий. Первое совпадение прохождения через замену дает этот набор событий:
a | a* | Starting regex match
a | a* | Trying a literal character zero-or-more times (as many as possible)
| a* | Matched
| | Regex matched in 3 steps
Это показывает, что "a" сопоставляется в первый раз, который заменяется на "e".
После завершения матча в первый раз отладчик позволяет запустить второе совпадение из одной и той же программы:
| <~~ | Back-tracking in regex
| a* | Back-tracked and restarting regex match
| a* | Trying a literal character zero-or-more times (as many as possible)
| a* | Matched
| | Regex matched in 3 steps
Это показывает, что "" после оригинала "a" (теперь "e" ) совпадает со вторым и заменяется на "e".
К сожалению, либо я не знаю, как читать результат, либо Regexp:: Debugger запутывается в этот момент или что-то в этом роде, но он повторяется снова, но не выполняет замену.
| <~~ | Back-tracking in regex
| a* | Back-tracked and restarting regex match
| a* | Trying a literal character zero-or-more times (as many as possible)
| a* | Matched
| | Regex matched in 3 steps
В любом случае, Perl уже третий раз соглашается и решает по какой-то причине не выполнять замену на этот раз или Regexp:: Debugger, или я просто смущен.
Изменить: Я решил свою путаницу, просмотрев perldoc perlre:
"Петли более высокого уровня сохраняют дополнительное состояние между итерациями: было ли последнее совпадение нулевым. Чтобы разбить цикл, следующее совпадение после совпадения нулевой длины запрещено иметь длину нуля. Этот запрет взаимодействует с обратным трассировкой (см." Возврат в исходное положение"), поэтому второе наилучшее совпадение выбирается, если наилучшее совпадение имеет нулевую длину.
Ответ 3
Во-первых, как говорили люди, a*
жадный; он не будет соответствовать пустой строке, если он может соответствовать "a". Во-вторых, совпадение /g
будет соответствовать столько раз, сколько возможно, но это не приведет к совпадению нулевой длины два раза подряд в той же позиции., Так как это означает, что шаблон не прогрессирует. Шаблон вынужден сделать какое-то другое совпадение, отличное от нуля, если оно может, или же сбой.
При запуске s/a*/e/g
на "a" сначала a*
соответствует "a" в позиции 0 (и переходит в позицию 1), поэтому "a" заменяется на "e". Затем a*
соответствует пустой строке в позиции 1 (и не продвигается), поэтому "" заменяется на "e". Теперь мы все еще находимся в позиции 1, а a*
запрещается снова сопоставлять пустую строку и больше не может соответствовать, поэтому шаблон не работает, и perl пытается перейти к следующему символу в строке. Но мы достигли конца строки, поэтому выход "ee".
При запуске s/a*/e/g
на "b" сначала a*
соответствует пустой строке в позиции 0 (и не продвигается), заменяя "" на "e". Тогда другое совпадение в позиции 0 запрещено, поэтому шаблон переходит в положение 1 (переходящий "b", который не заменяется). Затем a*
соответствует пустой строке в позиции 1 и заменяет ее на "e"; и опять же, ему запрещено совмещать дважды в одном и том же положении, и perl не может продвигаться за пределы строки, поэтому результат "ebe".
Наконец, представьте, что вы выполняете s/a*/e/g
на "ab". a*
соответствует "aa" в позиции 0, заменяется на "e" и переходит к позиции 2; a*
соответствует пустой строке в позиции 2, заменяется на "e" и не продвигается; a*
не может выполнить непустое совпадение и не выполняется; "b" сканируется; a*
соответствует пустой строке в позиции 3, заменяется на "e" и не продвигается; конец строки. Таким образом, результат "eebe", как подтвердит perl.
Ответ 4
Вы считаете, что это противоречиво, потому что вы думаете, что он заменяет "пустую строку в pos 0", когда она фактически заменяет "последовательности" a at pos 0 ". Вы не должны удивляться тому, что последовательность длиннее, когда вход a
по сравнению с b
.
$_ = "a"; s/a*/e/g
:
- Попробуйте в pos 0: Match 1 char в pos 0. Pos = 1.
- Попробуйте в pos 1: Match 0 char в pos 1. Pos = 1.
- Попробуйте в pos 1:
Match 0 char в pos 1. Увы, уже сделал это, так что не сработайте в этой позиции. Pos = 2.
$_ = "b"; s/a*/e/g
:
- Попробуйте в pos 0: Match 0 char в pos 0. Pos = 0.
- Попробуйте в pos 0:
Match 0 char at pos 0. Увы, уже сделал это, так что сбой в этой позиции. Pos = 1.
- Попробуйте в pos 1: Match 0 char в pos 1. Pos = 1.
- Попробуйте в pos 1:
Match 0 char в pos 1. Увы, уже сделал это, так что не сработайте в этой позиции. Pos = 2.
Если вы хотите сопоставить пустую строку в pos 0, вам придется попросить ее сделать это.
>perl -E"say 'a' =~ s/^|a*/e/gr;"
eee
>perl -E"say 'b' =~ s/^|a*/e/gr;"
ebe
Ответ 5
Очень любопытно. Используя Perl 5.12.1 на RHEL 5, вывод действительно выглядит так:
$ perl -e '$_ = "a"; s/a*/e/g; print "$_\n";'
ee
$
Лучшая догадка (причина), которую я могу придумать, состоит в том, что a*
сначала соответствует a
, уступая первому e
, а затем соответствует пустой строке после a
, для второго e
. Попробуйте несколько вариантов:
$ perl -e '$_ = "a"; s/^a*/e/g; print "$_\n";'
e
$ perl -e '$_ = "a"; s/a*$/e/g; print "$_\n";'
ee
$ perl -e '$_ = "a"; s/a+/e/g; print "$_\n";'
e
$
Первый и третий из этих вариантов дают ответы, которые я ожидаю. Второй меня все еще озадачивает.
$ perl -e '$_ = "a\n"; s/a*/e/g; print "$_\n";'
ee
e
$
Хммм...