Подтвердить что ты не робот

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 с левой стороны как правая сторона!

4b9b3361

Ответ 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
$

Хммм...