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

Регулярные выражения в 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) и скриптовую валидацию.