Примечание:
* Мой пост с вопросом содержит два связанных, но разных вопроса , для которых я должен был создать отдельные посты, как я теперь понимаю.
* Другие ответы здесь сосредоточены на по одному вопросов каждый, поэтому отчасти этот ответ дает дорожную карту того, какие ответы отвечают на какой вопрос .
Что касается того, почему такие шаблоны, как $<expr>
разрешены / когда они имеют смысл:
ответ Дога утверждает, что бессмысленные комбинации, такие как $.+
, вероятно, , не предотвращаются по прагматическим причинам; исключение их может не стоить усилий.
Ответ Тима показывает, как определенные выражения могут имеют смысл после $
, а именно отрицательный взгляд за утверждениями .
Вторая половина ответа Ивана_Поздеева ответа убедительно синтезирует ответы Дога и Тима.
Что касается того, почему глобальное соответствие находит два совпадения для таких шаблонов, как .*
и .*$
:
- ответ revo содержит отличную справочную информацию о сопоставлении нулевой длины (с пустой строкой), к чему и сводится проблема в конечном итоге .
Позвольте мне дополнить его ответ, связав его более непосредственно с тем, как поведение противоречит моим ожиданиям в контексте глобального соответствия:
С чисто точки зрения здравого смысла очевидно, что как только вход был полностью использован во время сопоставления, по определению ничего не осталось , поэтому нет причин искать дальнейшие совпадения.
В отличие от этого, большинство движков регулярных выражений рассматривают положение символа после последнего символа входной строки - в некоторых случаях положение, известное как конец строки субъекта двигатели - допустимая стартовая позиция для матча и, следовательно, попытка другого .
Если имеющееся регулярное выражение совпадает с пустой строкой (создает совпадение нулевой длины; например, регулярные выражения, такие как .*
или a?
), оно соответствует этой позиции и возвращает пустую строку матч.
И наоборот, вы не увидите дополнительного совпадения, если регулярное выражение не (также) не совпадает с пустой строкой - в то время как дополнительное совпадение все еще пыталось во всех случаях, совпадение не будет быть найденным в этом случае, учитывая, что пустая строка - единственное возможное совпадение в позиции конца предметной строки.
Хотя это предоставляет техническое объяснение поведения, оно все равно не сообщает нам почему соответствует после последнего символа, который был реализован.
Самая близкая вещь, которую мы имеем, - это образованное предположение от Wiktor Stribiżew в комментарии (выделение добавлено), которое снова предлагает прагматическую причину поведения :
... как при получении совпадения с пустой строкой, вы все равно можете сопоставить следующий символ с тем же индексом в строке. Если механизм регулярных выражений не поддерживает его, эти совпадения будут пропущены. Создание исключения для конца строки, вероятно, было не столь критично для авторов движка регулярных выражений .
Первая половина ответа ivan_pozdeev объясняет поведение более технически подробно, говоря нам, что пустое поле в конце строки [input] является допустимой позицией для сопоставления, как и любая другая символьная граница позиция.
Однако, хотя обработка всех таких позиций однозначно внутренне непротиворечива и, по-видимому, упрощает реализацию , поведение по-прежнему не поддается здравому смыслу и не имеет очевидных преимуществ для пользователя .
Дополнительные наблюдения по сопоставлению пустой строки:
Примечание. Во всех приведенных ниже фрагментах кода глобальная строка замена выполняется для выделения итоговых совпадений: каждое совпадение заключено в [...]
, тогда как несоответствующие части входных данных передаются черезкак есть.
Обратите внимание, однако, что сопоставление в позиции конца предметной строки не ограничено теми механизмами, где сопоставление продолжается с таким же символомпозиция после совпадения пусто .
Например, механизм регулярных выражений .NET не делает это (пример PowerShell):
PS> 'a1' -replace '\d*|a', '[$&]'
[]a[1][]
То есть:
\d*
соответствует пустой строке до a
a
, а затем не ,это означает, что позиция символа была продвинутой после пустого соответствия. 1
было сопоставлено с \d*
- Позиция конца строки объекта быласнова соответствует
\d*
, что приводит к другому совпадению с пустой строкой.
Perl 5 является примером механизма, который возобновляет сопоставление при в том же позиция символа:
$ "a1" | perl -ple "s/\d*|a/[$&]/g"
[][a][1][]
Обратите внимание, что a
также сопоставлялось.
Интересно, что Perl 6 не только ведет себя по-разному.у, но демонстрирует еще один вариант поведения:
$ "a1" | perl6 -pe "s:g/\d*|a/[$/]/"
[a][1][]
По-видимому, если чередование находит и и пустое и непустое совпадение, сообщается только о непустом - см.Комментарий Revo ниже.