Доллар в регвыражениях не всегда означает конец строки

Долго боролся сейчас с одним багом, поэтому пишу себе, чтобы не забыть.

Есть регулярное выражение (для примера):

/(some|any)thing$/i

Доллар, уверен я, означает «конец строки». Выражение должно проверять, что строка заканчивается на слово something или anything в любом регистре. Но вот оно иногда срабатывает, даже если строка не заканчивается на него! Я в отчаянии уже проверяю впрямую, что строка заканчивается на g или G, и точно вижу, что она не заканчивается. А выражение срабатывает!

Замечаю, что это происходит, если в конце выражения стоит возврат каретки. Думаю: какого хрена? У меня же написан доллар сразу после g, никаких возвратов каретки там! Модификатора /m, который разделяет текст на отдельные строки, нет. Может, он как-то там по умолчанию включился, и надо его, наоборот, отключить?

От безысходности иду читать документацию. Никакого антонима модификатору /m не нахожу. Читаю про сам /m:

m (PCRE_MULTILINE)
By default, PCRE treats the subject string as consisting of a single «line» of characters (even if it actually contains several newlines). The «start of line» metacharacter (^) matches only at the start of the string, while the «end of line» metacharacter ($) matches only at the end of the string, or before a terminating newline (unless D modifier is set).

Что? Что ещё за нахрен /D?

D (PCRE_DOLLAR_ENDONLY)
If this modifier is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this modifier, a dollar also matches immediately before the final character if it is a newline (but not before any other newlines).

Как же можно было такую дичь придумать? Исправляю регулярное выражение:

/(some|any)thing$/iD

А также запоминаю, что надо теперь вообще всегда использовать модификатор /D, потому что если блин мне надо возврат каретки мэтчить, я это в состоянии впрямую сформулировать внутри регвыражения, а не полагаться на это хитрожопое исключение.

Подписаться на блог
Отправить
Дальше
3 комментария
Михаил 11 мес

Как же можно было такую дичь придумать?

Как будто всё остальное в PHP сделано хоть немножко разумно... (Вон даже в документации — «dollar metacharacter» вместо «$ metacharacter» — чтобы никто поиском не нашёл.)

Илья Бирман 11 мес

Я рад, что вам не нравится ПХП, но язык регулярных придумали не авторы ПХП — это из Перла.

Михаил 11 мес

Язык регулярных выражений придумали задолго до Перла, а в Перле он был расширен до более практичного (поэтому это называется именно «PCRE», не просто «RE», которые гораздо беднее). В отличие от ПХП, у Перла есть вменяемая документация (https://perldoc.perl.org/perlretut), в которой прямо написано про поведение по умолчанию («’.’ matches any character except „\n“ ... ’$’ matches only at the end or before a newline at the end») и почему оно наиболее разумно для языка, разработанного для обработки текстовых файлов, обычно построчной. В том же разделе (в пределах одной экранной страницы, с подробными примерами) описаны модификаторы «/s» и «/m», а также разница между «$», «\Z» и «\z» (последний как раз «matches only the end»).

Илья Бирман 11 мес

Что невменяемого в документации ПХП? Я ж её процитировал, в ней тоже это написано. Проблема не в документации, а в дизайне.

Михаил 11 мес

Что невменяемого в документации ПХП?

  1. Насколько я понимаю, на ПХП вы программируете не первый год и профессионально, т. е. документацию должны были читать, тем не менее на особенности поведения «$» она либо вообще не обратила вашего внимания, либо не способствовала запоминанию.
  2. В хорошую документацию смотрят первым делом, а в плохую — действительно «от безысходности».
  3. Документация ПХП зачем-то разбита на мелкие куски без адекватных гиперссылок или хотя бы «см. также», а поиск сломан (см. мой изначальный комментарий).
  4. Правильный ответ (на самом деле «конец строки» обозначается «\z») вы так и не нашли.
  5. Проблема, связанная с проблемой в дизайне (опять см. мой изначальный комментарий). В Перле поведение «$» разумное для его типичных задач и аргументировано в документации. В ЭКМАСкрипте (JS) поведение «$» другое, но тоже разумное для его типичных задач. В ПХП поведение «$» бессмысленно передрано из Перла (вместо более близкого по задачам JS), при этом в документации никак не аргументировано, зато она содержит раздел «Differences From Perl», но не содержит «Differences From JS», который для типичных пользователей ПХП был бы гораздо полезнее и понятнее.
Мои книги