Методы RegExp в JavaScript
Регулярные выражения в JavaScript — мощный инструмент поиска и обработки строк. Разбираем ключевые методы RegExp и String.
Регулярные выражения в JavaScript — мощный способ поиска, сопоставления и обработки строк. В этом руководстве рассматриваются ключевые методы, которые вызываются на регулярном выражении (test, exec) и на строке (search, split, match, matchAll, replace, replaceAll), с выполняемыми примерами и реальной формой возвращаемых значений для каждого из них. Понимание этих методов позволяет эффективно работать с сопоставлением шаблонов в вашем коде.
Краткое напоминание о регулярных выражениях
Прежде чем перейти к методам, сделаем однминутный обзор для читателей, не знакомых с регулярными выражениями.
Литерал регулярного выражения записывается между слешами, за которыми могут следовать флаги:
/pattern/flags // e.g. /hello/giРегулярное выражение также можно создать динамически с помощью конструктора RegExp — это удобно, когда шаблон берётся из переменной (обратите внимание: обратные слеши внутри строки нужно удваивать):
const word = "hello";
const regex = new RegExp(word, "gi"); // same as /hello/gi
const digits = new RegExp("\\d+"); // same as /\d+/Флаги изменяют поведение сопоставления:
| Флаг | Название | Эффект |
|---|---|---|
g | global | Находить все совпадения, а не останавливаться на первом. |
i | ignore case | Делать сопоставление нечувствительным к регистру. |
m | multiline | ^ и $ совпадают у переносов строки, а не только у начала и конца строки. |
s | dotAll | Позволить . также совпадать с символами новой строки. |
u | unicode | Обрабатывать шаблон как последовательность кодовых точек Unicode. |
y | sticky | Совпадение только начиная точно с позиции lastIndex. |
Полный синтаксис шаблонов и описание флагов см. в разделах Шаблоны и флаги JavaScript и Захватывающие группы. Многие из приведённых ниже методов также описаны со стороны строк в разделе JavaScript Strings.
RegExp.test()
Метод test() проверяет строку на соответствие регулярному выражению. Возвращает true, если совпадение найдено, или false в противном случае.
Пример
В этом примере метод test() проверяет, содержит ли строка "Hello world!" шаблон "hello". Поскольку метод чувствителен к регистру, он возвращает false. Добавьте флаг i (/hello/i) — и он вернёт true.
RegExp.exec()
Метод exec() ищет в строке совпадение с регулярным выражением. Возвращает array, содержащий совпавший текст и захватывающие группы, или null, если совпадение не найдено. Возвращаемое значение — не обычный array: оно также содержит index (позиция начала совпадения), input (исходная строка) и groups (именованные захватывающие группы или undefined, если их нет).
Пример
Здесь exec() находит одну или несколько цифр в "The year is 2024." Элемент 0 — полное совпадение, элемент 1 — первая захватывающая группа (\d+), а дополнительные свойства указывают, где было найдено совпадение.
Особенность lastIndex при использовании /g
Когда регулярное выражение имеет флаг global (g) или sticky (y), exec() становится «состоятельным»: каждый вызов продолжает с позиции lastIndex регулярного выражения и продвигает её вперёд, возвращая null, когда совпадений больше нет. Вызывайте его в цикле для обхода всех совпадений — но учтите, что повторное использование одного и того же регулярного выражения с /g в несвязанных вызовах может дать неожиданные результаты, поскольку lastIndex запоминается.
Без флага g метод exec() не является «состоятельным» и всегда возвращает первое совпадение, поэтому такой цикл while выполнялся бы бесконечно. Для неглобального использования предпочтительнее match() или matchAll().
String.search()
Метод search() проверяет строку на соответствие регулярному выражению. Возвращает индекс (начиная с нуля) первого совпадения или -1, если совпадение не найдено.
Пример
В этом примере метод search() возвращает индекс первого вхождения "awesome" в строке, равный 14.
String.split()
Метод split() разделяет строку на упорядоченный список подстрок и возвращает их в array. Это универсальный строковый метод: разделитель может быть как обычной строкой (str.split(",")), так и регулярным выражением. Форма с регулярным выражением удобна, когда разделитель варьируется — например, при разбивке по одному или нескольким пробельным символам.
Пример
Первый вызов разбивает по литеральной запятой; второй использует регулярное выражение /\s+/ для разбивки по любой последовательности пробельных символов, так что несколько пробелов и символы табуляции превращаются в аккуратные разделители.
String.match()
Метод match() получает результат сопоставления строки с регулярным выражением. Возвращаемое значение зависит от флагов:
- С
/g: array всех совпавших подстрок (безindexиgroups) илиnull, если совпадений нет. - Без
/g: тот же расширенный array, который возвращаетexec()— первое совпадение плюс захватывающие группы, сindex,inputиgroups— илиnull, если совпадения нет.
Поскольку match() возвращает null, а не пустой array, когда ничего не найдено, всегда проверяйте результат перед использованием.
Пример
С глобальным флагом match() возвращает каждое вхождение "ain"; шаблон, который не совпадает, возвращает null, а не пустой array.
String.matchAll()
Метод matchAll() возвращает итератор всех совпадений, включая захватывающие группы. Каждый элемент — полный array совпадения (RegExpMatchArray), той же формы, что и результат exec(), — поэтому каждое совпадение содержит index, input и groups, а не только совпавшие строки. Регулярное выражение обязательно должно иметь флаг g, иначе matchAll() бросит TypeError. В отличие от exec() в цикле, matchAll() не оставляет остаточного lastIndex в регулярном выражении, что делает его более чистым вариантом для перебора всех совпадений. (Требуется ES2020+.)
Пример
Поскольку элементы являются настоящими array совпадений, можно читать match.index и захваченные группы (match[1], match[2], …) для каждого результата. Преобразуйте итератор в array с помощью Array.from(str.matchAll(regex)) или оператора spread, когда нужно обращаться к результатам по индексу.
String.replace()
Метод replace() возвращает новую строку с заменёнными совпадениями шаблона (исходная строка никогда не изменяется). С обычной строкой или регулярным выражением без /g заменяет только первое совпадение; добавьте флаг g, чтобы заменить все.
Строка замены поддерживает специальные токены: $& — всё совпадение, $` и $' — текст до и после него, $n вставляет n-ю захватывающую группу, а $<name> вставляет именованную группу.
Пример
В качестве замены также можно передать функцию; она получает совпадение и захваченные группы в качестве аргументов и возвращает текст замены — удобно для вычисляемых значений:
String.replaceAll()
Метод replaceAll() заменяет каждое вхождение и возвращает новую строку. Если передать регулярное выражение, оно обязательно должно иметь флаг g, иначе будет брошен TypeError — это защищает от распространённой ошибки, когда ожидают, что replace() будет работать глобально. Поддерживает те же токены замены $1 / $<name> и функции-заменители, что и replace(). (Требуется ES2021+.)
Пример
Используйте replaceAll() с обычной строкой, когда нужно просто заменить все копии литеральной подстроки; форму с регулярным выражением — когда целью является шаблон.
Заключение
В этом руководстве рассмотрены основные методы работы с регулярными выражениями в JavaScript: test и exec — на стороне регулярного выражения, и search, split, match, matchAll, replace и replaceAll — на стороне строки, — а также реальная форма возвращаемых значений и «состоятельное» поведение lastIndex при флаге /g. Чтобы глубже изучить сами шаблоны, продолжите чтение разделов Шаблоны и флаги, Захватывающие группы и Флаг sticky y.