Регулярные выражения в JavaScript
RegExp - поиск и обработка текста
Регулярное выражение (RegExp) — шаблон для поиска и обработки текста — проверить email, вытащить числа из строки, заменить формат даты. В JavaScript RegExp — отдельный тип данных; с ним работают методы строк и сам объект RegExp.
Связь: общий справочник по синтаксису шаблонов — RegEx в энциклопедии; готовые шаблоны email, телефона, даты — Regex — готовые паттерны; атрибут pattern в HTML — в основных HTML-тегах; базовые методы строк (includes, slice, replace) — в типах данных JS; справочник — в справочнике по JavaScript; валидация форм из скрипта — в валидации форм.
Быстрый вход за минуту
Если вы только начинаете, держите рабочую связку из трёх шагов:
- Сначала пишите простой шаблон и проверяйте
test. - Потом добавляйте группы
(...), если нужно извлечь части строки. - Для изменения текста переходите на
replace.
const phone = '+7 (999) 123-45-67';
const onlyDigits = phone.replace(/\D/g, ''); // 79991234567
const isRuMobile = /^7\d{10}$/.test(onlyDigits); // true
Разбор:
replace(/\D/g, '')удаляет все нецифровые символы —\Dозначает "любой символ, кроме цифры", флагgприменяет замену по всей строке.onlyDigitsполучает нормализованный формат номера, удобный для дальнейшей проверки и отправки в API.- Шаблон
^7\d{10}$проверяет номер целиком —^начало строки,7обязательная первая цифра,\d{10}ещё десять цифр,$конец строки. test(...)возвращает булево значение, поэтому эта запись хорошо подходит дляifи inline-валидации формы.- Такой подход разделяет задачу на два этапа: сначала очистка входа, затем строгая валидация формата.
Это уже покрывает множество задач в интерфейсах и API-валидации.
Создание и флаги
Два способа задать шаблон:
const a = /^\d{2}-\d{2}-\d{4}$/; // литерал
const b = new RegExp('^\\d{2}-\\d{2}-\\d{4}$'); // конструктор — удобен, когда шаблон собирается из переменных
Разбор:
- Переменная
aиспользует литерал RegExp: этот способ короче и обычно читается быстрее в статическом коде. - В
new RegExp(...)обратный слеш экранируется дважды (\\d), потому что шаблон задаётся строкой JavaScript. - Конструкция
\d{2}требует ровно две цифры, дефис-совпадает буквально, а\d{4}задаёт блок из четырёх цифр. - Якоря
^и$исключают частичные совпадения внутри длинной строки. - Конструктор полезен, когда шаблон собирается динамически, например из пользовательских настроек фильтра.
| Флаг | Назначение |
|---|---|
g | все совпадения, не только первое; меняет lastIndex |
i | без учёта регистра |
m | ^ и $ привязаны к строке, а не ко всему тексту |
s | . захватывает перевод строки |
u | Unicode (суррогатные пары, \p{...}) |
y | "липкий" поиск с позиции lastIndex |
d | в результате есть indices (диапазоны символов) |
/привет/gi.test('Привет, мир'); // true
Разбор:
- Флаг
iвключает регистронезависимое сравнение, поэтомуприветсовпадает сПривет. - Флаг
gобычно нужен для множественных совпадений; вtestон может менятьlastIndexу одного и того же объекта RegExp. - Метод
testпроверяет наличие совпадения и сразу возвращаетtrue/falseбез массива групп. - Эта форма удобна для быстрых проверок "встречается ли фрагмент текста" перед более тяжёлой обработкой.
Основные элементы шаблона
| Конструкция | Смысл |
|---|---|
. | любой символ (кроме перевода строки, если нет s) |
\d, \w, \s | цифра, "слово", пробел |
\D, \W, \S | инверсии |
[a-z] | один символ из набора |
[^0-9] | один символ не из набора |
* + ? | 0+, 1+, 0 или 1 |
{3} {2,5} {3,} | точное и диапазонное число повторений |
? после квантификатора | ленивый режим: .*? |
^ $ | начало и конец (строки или строки в режиме m) |
| | альтернатива: cat|dog |
Группы:
(sub)— захватывающая, попадает вmatch[1],match[2]…(?:sub)— без захвата, только группировка(?<name>sub)— именованная группа,match.groups.name
Границы слова: \b — между "словесным" и "несловесным" символом.
Утверждения (lookahead / lookbehind) — проверка контекста без "съедания" символов:
| Конструкция | Смысл |
|---|---|
(?=...) | дальше по строке должно совпасть ... |
(?!...) | дальше не должно совпасть |
(?<=...) | слева должно совпасть (lookbehind) |
(?<!...) | слева не должно совпасть |
Пример: пароль минимум 8 символов и хотя бы одна цифра — ^(?=.*\d).{8,}$. Подробная таблица assert-выражений и флагов — в общем справочнике RegEx.
Методы — что вызывать
У RegExp
/\d+/.test('abc123'); // true — есть ли совпадение
/\d+/g.exec('a1 b22'); // ['1', ...], при повторных вызовах — следующие
Разбор:
\d+означает "одна или более цифр подряд", поэтому вabc123шаблон находит подпоследовательность123.testотвечает только на вопрос "есть совпадение или нет", без деталей о позициях и группах.execвозвращает массив первого найденного совпадения и служебные поля (index,input).- С флагом
gповторные вызовыexecна том же объекте продолжают поиск с позицииlastIndex. - Такой цикл на
execудобен, когда нужно последовательно обработать каждое найденное число.
С флагом g у одного и того же объекта RegExp растёт lastIndex — при цикле while ((m = re.exec(s)) !== null) не забывайте сбрасывать re.lastIndex = 0 перед новой строкой.
У строки
'2024-05-25'.match(/(\d{4})-(\d{2})-(\d{2})/);
// ['2024-05-25', '2024', '05', '25', index: 0, groups: undefined]
'one two three'.matchAll(/\w+/g); // итератор всех совпадений
'price: 100 руб'.replace(/(\d+)/, '≈$1'); // price: ≈100 руб
' hello '.replace(/^\s+|\s+$/g, ''); // trim-подобная очистка
Разбор:
match(/(\d{4})-(\d{2})-(\d{2})/)возвращает массив, где первый элемент — полное совпадение, а следующие — захваченные группы года, месяца и дня.matchAll(/\w+/g)возвращает итератор всех совпадений и полезен для проходаfor...of, когда нужны и группы, и позиции.- В
replace(/(\d+)/, '≈$1')подстановка$1вставляет содержимое первой группы в новый текст. - Шаблон
/^\s+|\s+$/gубирает пробелы в начале или в конце строки:^и$ограничивают область,|задаёт альтернативу. - Эти методы образуют полный цикл обработки — найти, извлечь, преобразовать и нормализовать строку.
replace со вторым аргументом-функцией удобен для сложной подстановки:
'user_12_post_3'.replace(/_(\d+)_/g, (_, id) => ` #${id} `);
Разбор:
- Шаблон
_(\d+)_ищет число между двумя символами подчёркивания и кладёт число в первую группу. - Первый аргумент колбэка (
_) — полное совпадение, оно не нужно, поэтому используется нейтральное имя. - Второй аргумент
id— содержимое группы(\d+), его можно форматировать как нужно. - Функция-заменитель полезна, когда простых плейсхолдеров
$1,$2недостаточно и нужна логика. - Флаг
gобрабатывает каждое подходящее вхождение, а не только первое.
split с RegExp режет по шаблону:
'a,b; c'.split(/[,;]\s*/); // ['a', 'b', 'c']
Разбор:
- Символьный класс
[,;]задаёт разделители запятую или точку с запятой. \s*"съедает" ноль и более пробельных символов после разделителя.splitвозвращает массив чистых токенов без ручногоtrimдля каждого элемента.- Такой шаблон удобен для импорта списков тегов из свободного пользовательского ввода.
Типичные задачи
Проверка формата
function isEmail(value) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(value).trim());
}
Разбор:
String(value).trim()нормализует вход: функция корректно обрабатывает нестроковые значения и удаляет крайние пробелы.- Конструкция
[^\s@]+требует хотя бы один символ, который не является пробелом и@. - Символ
@в шаблоне обязателен ровно один раз между локальной и доменной частью. \.проверяет точку буквально, без экранирования.означал бы любой символ.- Проверка охватывает частый практический формат email и подходит для клиентского UX до серверной валидации.
Для продакшена часто достаточно type="email" и Constraint Validation API; RegExp нужен для нестандартных правил.
Извлечение данных
const log = 'ERROR 2024-05-25 14:03:12 disk full';
const m = log.match(/^(\w+)\s+(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+(.+)$/);
if (m) {
const [, level, date, time, message] = m;
}
Разбор:
- Шаблон фиксирует структуру строки лога — уровень, дата, время и текст сообщения в отдельных группах.
\s+допускает один или более пробелов между блоками и устойчив к разной ширине разделителей.- Группа
(.+)в конце забирает остаток строки целиком как сообщение. - Деструктуризация
const [, level, date, time, message]пропускает полный матч и сразу выдаёт именованные переменные. - Условие
if (m)защищает от ошибок при отсутствии совпадения и делает код безопасным.
Замена с сохранением структуры
const masked = 'ИНН 7707083893'.replace(/\b(\d{2})\d{5}(\d{2})\b/, '$1*****$2');
Разбор:
\bограничивает поиск границами слова и снижает риск частичного совпадения внутри длинной последовательности.- Группы
(\d{2})и(\d{2})сохраняют первые и последние две цифры исходного значения. - Средняя часть
\d{5}не сохраняется и заменяется на маску*****. - Подстановка
$1*****$2собирает финальную строку с сохранением контрольных фрагментов. - Такой паттерн подходит для безопасного показа чувствительных данных в UI и логах.
Ошибки и ограничения
- Слишком сложный шаблон — "ад регулярок" для email/URL; проще опереться на встроенные типы полей HTML или библиотеку валидации на сервере.
- Глобальный RegExp в общем модуле — общий
lastIndexломает параллельные вызовы; создавайте новый/.../gна вызов или сбрасывайтеlastIndex. - Катастрофический backtracking — вложенные квантификаторы
(a+)+на длинной строке тормозят вкладку; упрощайте шаблон или ограничивайте длину входа. - Не путать с парсером — JSON, XML и HTML надёжнее разбирать специализированными парсерами, а не одним большим RegExp.
Когда что использовать
| Задача | Подход |
|---|---|
| Простая маска телефона, код | RegExp + test / replace |
| Поля формы в браузере | HTML pattern, type, затем валидация из JS |
| Массовая обработка логов | RegExp или разбор по разделителям |
| Сложный язык (SQL, код) | Парсер, не RegExp |
Краткий итог
RegExp в JavaScript — связка шаблона, флагов и методов test / exec / match / replace. Начинайте с литерала /.../, именованных групп для читаемости и явного сброса lastIndex при флаге g. Для форм сочетайте разметку, CSS (:valid) и скриптовую валидацию.