Перейти к основному содержимому

Регулярные выражения в JavaScript

Разработчику Архитектору

RegExp - поиск и обработка текста

Регулярное выражение (RegExp) — шаблон для поиска и обработки текста — проверить email, вытащить числа из строки, заменить формат даты. В JavaScript RegExp — отдельный тип данных; с ним работают методы строк и сам объект RegExp.

Связь: общий справочник по синтаксису шаблонов — RegEx в энциклопедии; готовые шаблоны email, телефона, даты — Regex — готовые паттерны; атрибут pattern в HTML — в основных HTML-тегах; базовые методы строк (includes, slice, replace) — в типах данных JS; справочник — в справочнике по JavaScript; валидация форм из скрипта — в валидации форм.


Быстрый вход за минуту

Если вы только начинаете, держите рабочую связку из трёх шагов:

  1. Сначала пишите простой шаблон и проверяйте test.
  2. Потом добавляйте группы (...), если нужно извлечь части строки.
  3. Для изменения текста переходите на 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. захватывает перевод строки
uUnicode (суррогатные пары, \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&#123;4&#125;)-(\d&#123;2&#125;)-(\d&#123;2&#125;)/) возвращает массив, где первый элемент — полное совпадение, а следующие — захваченные группы года, месяца и дня.
  • 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} не сохраняется и заменяется на маску &#42;&#42;&#42;&#42;*.
  • Подстановка $1&#42;&#42;&#42;&#42;*$2 собирает финальную строку с сохранением контрольных фрагментов.
  • Такой паттерн подходит для безопасного показа чувствительных данных в UI и логах.

Ошибки и ограничения

  1. Слишком сложный шаблон — "ад регулярок" для email/URL; проще опереться на встроенные типы полей HTML или библиотеку валидации на сервере.
  2. Глобальный RegExp в общем модуле — общий lastIndex ломает параллельные вызовы; создавайте новый /.../g на вызов или сбрасывайте lastIndex.
  3. Катастрофический backtracking — вложенные квантификаторы (a+)+ на длинной строке тормозят вкладку; упрощайте шаблон или ограничивайте длину входа.
  4. Не путать с парсером — JSON, XML и HTML надёжнее разбирать специализированными парсерами, а не одним большим RegExp.

Когда что использовать

ЗадачаПодход
Простая маска телефона, кодRegExp + test / replace
Поля формы в браузереHTML pattern, type, затем валидация из JS
Массовая обработка логовRegExp или разбор по разделителям
Сложный язык (SQL, код)Парсер, не RegExp

Краткий итог

RegExp в JavaScript — связка шаблона, флагов и методов test / exec / match / replace. Начинайте с литерала /.../, именованных групп для читаемости и явного сброса lastIndex при флаге g. Для форм сочетайте разметку, CSS (:valid) и скриптовую валидацию.