Регулярки в 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.

Узнал об этом из канала Ильи Бирмана.