JS / Основы
Регулярные выражения в JavaScript: практическое введение
Синтаксис RegExp, флаги, классы символов, квантификаторы, группы и методы строк на понятных примерах.
Содержание статьи
Регулярное выражение описывает шаблон текста. С его помощью можно найти числа, заменить повторяющиеся пробелы или проверить простой формат. Для сложного синтаксиса вроде полноценного email, URL или HTML регулярное выражение часто хуже специализированного парсера.
Начинайте с небольшой задачи и проверяйте шаблон на подходящих и неподходящих примерах.
Создание RegExp
Литерал подходит для постоянного шаблона:
const errorCodePattern = /ERR-\d{4}/;Конструктор нужен, когда часть шаблона формируется во время выполнения:
const digitsCount = 4;const errorCodePattern = new RegExp(`ERR-\\d{${digitsCount}}`);В строке обратный слеш экранируется ещё одним слешем. Если шаблон не динамический, литерал читается проще.
Не вставляйте пользовательский текст в RegExp без экранирования специальных символов.
Проверка через test()
const productCodePattern = /^WEB-\d{4}$/;console.log(productCodePattern.test('WEB-2026')); // trueconsole.log(productCodePattern.test('X-WEB-2026')); // false^ и $ привязывают шаблон к началу и концу строки. Без них test() нашёл бы подходящий фрагмент внутри более длинного текста.
Поиск через match()
const text = 'Заказы WEB-1024 и WEB-2048 готовы.';const codes = text.match(/WEB-\d{4}/g) ?? [];console.log(codes); // ['WEB-1024', 'WEB-2048']Флаг g ищет все совпадения. Без совпадений match() возвращает null, поэтому ?? [] удобен для дальнейшего перебора.
Для подробной информации о каждом совпадении используйте matchAll():
const matches = [...text.matchAll(/WEB-(\d{4})/g)];for (const match of matches) { console.log(match[0], match[1], match.index);}Классы символов
\d цифра ASCII 0–9\D не цифра\w буква ASCII, цифра или подчёркивание\W не \w\s пробельный символ\S не пробельный символ. почти любой символ, кроме перевода строки без флага s\w не включает русские буквы. Для Unicode-букв используйте property escapes с флагом u:
const wordPattern = /^\p{L}+$/u;console.log(wordPattern.test('Привет')); // trueconsole.log(wordPattern.test('Hello')); // trueСобственный класс задаётся квадратными скобками:
const hexColorPattern = /^#[0-9a-f]{6}$/i;[^...] означает отрицание внутри класса:
const nonDigits = /[^0-9]+/g;Квантификаторы
* ноль или больше+ один или больше? ноль или один{3} ровно три{2,} два или больше{2,5} от двух до пятиПример простого номера версии:
const versionPattern = /^v\d+(?:\.\d+){1,2}$/;console.log(versionPattern.test('v2.4')); // trueconsole.log(versionPattern.test('v2.4.1')); // trueТочка экранирована как \., потому что обычная . означает любой символ. (?:...) группирует без сохранения отдельного результата.
Группы и именованные группы
const datePattern = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/;const match = '2026-08-19'.match(datePattern);if (match?.groups) { console.log(match.groups.year); // '2026'}Шаблон проверяет форму, но не календарную корректность: строка 2026-99-99 тоже совпадёт. После regex нужно проверить диапазоны или использовать парсер даты.
Обратная ссылка требует повторения ранее найденного текста:
const repeatedWordPattern = /\b(?<word>[a-z]+)\s+\k<word>\b/gi;console.log('This is is repeated'.match(repeatedWordPattern)); // ['is is']Замена текста
const normalized = ' Один два\nтри ' .trim() .replace(/\s+/g, ' ');console.log(normalized); // 'Один два три'Если переносы строк нужно сохранить, заменяйте только пробелы и табы, а не весь класс \s.
Callback даёт контроль над заменой:
const result = 'Цена: 1500'.replace(/\d+/, (value) => { return new Intl.NumberFormat('ru-RU').format(Number(value));});Флаги
g— все совпадения;i— без учёта регистра;m—^и$работают для каждой строки;s— точка включает перевод строки;u— Unicode-режим;v— расширенный Unicode-режим и операции над классами в поддерживающих окружениях;y— поиск строго с позицииlastIndex.
Не добавляйте флаг «на всякий случай». Например, общий объект RegExp с g или y изменяет lastIndex, поэтому повторные вызовы test() могут чередовать результат:
const pattern = /a/g;console.log(pattern.test('a')); // trueconsole.log(pattern.test('a')); // falseДля одиночной проверки уберите g или создавайте новый объект.
Greedy и lazy
Квантификаторы по умолчанию жадные:
const text = '[один] и [два]';console.log(text.match(/\[.*\]/)?.[0]); // '[один] и [два]'console.log(text.match(/\[.*?\]/)?.[0]); // '[один]'Ещё точнее описать допустимое содержимое: /\[[^\]]*\]/.
Когда regex не нужен
- URL разбирайте через
new URL(); - числа — через
Number()с проверкойNumber.isFinite(); - HTML — через DOMParser или браузерный DOM, но не регулярным выражением;
- сложный email передавайте проверенному механизму и подтверждайте владение письмом;
- простое наличие подстроки проверяйте через
includes().
Что запомнить
Закрепляйте проверочный шаблон через ^ и $, учитывайте Unicode и отдельно тестируйте границы. Regex проверяет форму, но не всегда смысл. Чем сложнее выражение, тем важнее набор примеров и готовность заменить его специализированным парсером.