Регулярки в JavaScript не такие же, как в других языках
Скорее всего все знают, что разные языки программирования реализуют регулярные выражения по-разному. Самые навороченные реализации — в Perl и PHP. По крайней мере, так говорит сравнительная таблица в Википедии.
Однако я всегда думал, что языки вроде JavaScript реализуют просто подмножество PCRE. То есть, несмотря на различия в синтаксисе, регулярки в этих языках всё равно должны вести себя так же, как в более богатой на фичи реализации. Но, оказывается, это не так.
Например, в PCRE есть модификатор D. Его отсутствие меняет привычное для JS-разработчиков поведение $.
Вот, например, регулярка:
/token$/
Она матчится со строкой token:
> /token$/.test('token')
true
Но перестаёт матчиться, если добавить в конец символ новой строки:
> /token$/.test(`token
`)
false
По умолчанию $ пытается матчить конец всей строки, независимо от количества строк внутри неё. Чтобы изменить это поведение, в JS можно использовать модификатор m:
> /token$/m.test(`token
`)
true
Теперь регулярка матчится по строкам, а не по всей строке целиком.
Однако в PHP $ ведёт себя иначе. Там оба случая дают одинаковый результат:
> echo preg_match('/token$/', 'token');
1
> echo preg_match('/token$/', "token
");
1
(1 — это true, 0 — это false)
Почему? Потому что мы не указали модификатор D. Вот, как это объясняет документация PHP:
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). This modifier is ignored if m modifier is set. There is no equivalent to this modifier in Perl.
Иными словами, чтобы регулярка в PHP вела себя так же, как в JS, нужно добавить модификатор D:
> echo preg_match('/token$/D', 'token');
1
> echo preg_match('/token$/D', "token
");
0
Довольно раздражающая штука, если одновременно пишешь фронтенд на JS и бэкенд на PHP.
Узнал об этом из канала Ильи Бирмана.