Все статьи
Руководства

Регулярные выражения: полное руководство

Синтаксис regex, метасимволы, квантификаторы, группы, примеры, тестирование, частые паттерны.

16 апреля 2025
12 мин чтения
ConvertHub
#regex#регулярные#текст

Введение

Регулярные выражения (regex, regexp) — это компактный язык для описания шаблонов в тексте. С их помощью можно найти все email-адреса в документе, проверить, что телефон соответствует формату, извлечь домен из URL, заменить все вхождения слова с учётом словоформ, разобрать лог-файл на поля. Regex используется везде: от grep в командной строке до валидации форм в JavaScript, от парсинга логов в Python до написания компиляторов. В этом руководстве разберём синтаксис, метасимволы, квантификаторы, группы, lookahead и lookbehind, частые паттерны и типичные ошибки.

Базовый синтаксис

Регулярное выражение — это строка, в которой обычные символы означают сами себя, а специальные (метасимволы) задают правила. Простейший regexp — это просто строка:/hello/ найдёт подстроку «hello» в любом месте текста. Сложность начинается с метасимволов.

МетасимволЗначениеПример
.Любой символ (кроме переноса строки)a.c → «abc», «a1c», «a c»
\dЦифра (0–9)\d{3} → «123»
\DНе цифра\D+ → «abc»
\wБуква, цифра или подчёркивание\w+ → «hello_42»
\WНе \w
\sПробельный символ\s+ → « »
\SНе пробельный
^Начало строки^Hello → «Hello» в начале
$Конец строкиworld$ → «world» в конце
\bГраница слова\bcat\b → «cat», но не «category»

Квантификаторы

Квантификаторы указывают, сколько раз повторяется предыдущий элемент. Это один из самых мощных механизмов regex — позволяет описывать последовательности произвольной длины.

КвантификаторЗначениеПример
*0 или более разab*c → «ac», «abc», «abbc»
+1 или более разab+c → «abc», «abbc» (не «ac»)
?0 или 1 разcolou?r → «color», «colour»
{n}Ровно n раз\d{4} → «2025»
{n,}n или более раз\d{3,} → «123», «12345»
{n,m}От n до m раз\d{2,4} → «12», «123», «1234»

По умолчанию квантификаторы «жадные» (greedy) — захватывают максимально возможную часть текста. Это часто приводит к неожиданным результатам. Например,/".*"/ для строки "hello" "world" захватит всю строку целиком, включая обе кавычки, потому что * жадный. Чтобы сделать квантификатор «ленивым» (lazy), добавьте ?: /".*?"/найдёт две отдельные строки в кавычках.

const text = '"hello" "world"';

// Жадный квантификатор
text.match(/".*"/g);
// → ['"hello" "world"']  (одно совпадение, вся строка)

// Ленивый квантификатор
text.match(/".*?"/g);
// → ['"hello"', '"world"']  (два совпадения)

Классы символов и альтернативы

Класс символов — это набор символов в квадратных скобках, любой из которых может стоять в данной позиции. [aeiou] — любая гласная,[0-9] — то же, что \d, [a-zA-Z] — любая латинская буква. Знак ^ в начале класса инвертирует его:[^0-9] — любой символ, кроме цифр.

Альтернативы задаются через |: cat|dog|bird — любое из трёх слов. Альтернативы работают как логическое «или» и могут комбинироваться с группами: (cat|dog)s → «cats» или «dogs».

// Найти все слова, начинающиеся с гласной
const text = "Apple orange Banana apricot Cherry";
text.match(/\b[aeiouAEIOU]\w*/g);
// → ['Apple', 'orange', 'apricot']

// Валидация телефонного номера: +7 (XXX) XXX-XX-XX
const phoneRegex = /^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/;
phoneRegex.test("+7 (495) 123-45-67");  // true
phoneRegex.test("+74951234567");        // false

Группы и обратные ссылки

Скобки () создают группу — часть шаблона, которую можно использовать как единое целое. Группы нужны для трёх вещей: применения квантификаторов к подвыражению ((ab)+), извлечения частей совпадения и создания альтернатив ((cat|dog)). Каждая группа получает номер (1, 2, 3...) в порядке открывающей скобки, и к ней можно обратиться через обратную ссылку\1, \2 и т. д.

// Извлечение даты: YYYY-MM-DD
const dateRegex = /(\d{4})-(\d{2})-(\d{2})/;
const match = "2025-04-09".match(dateRegex);
// match[1] = "2025" (год)
// match[2] = "04"   (месяц)
// match[3] = "09"   (день)

// Обратная ссылка: найти повторяющиеся слова
const dupRegex = /\b(\w+)\s+\1\b/gi;
"hello hello world world".match(dupRegex);
// → ['hello hello', 'world world']

// Негруппирующая скобка (?:...)
const httpsRegex = /https?:\/\/(?:www\.)?example\.com/;

Если группа нужна только для логики, но не для извлечения, используйте негруппирующую конструкцию (?:...). Это ускоряет работу и упрощает нумерацию — негруппирующие скобки не получают номеров.

Lookahead и Lookbehind

Lookaround — это проверки, которые «заглядывают» вперёд или назад, не включая проверенный текст в совпадение. Lookahead позитивный (?=...) — совпадение, если после текущей позиции идёт указанный шаблон. Lookahead негативный (?!...) — совпадение, если НЕ идёт. Lookbehind позитивный (?<=...) и негативный (?<!...) — аналогично для предшествующего текста.

// Найти число, после которого идёт "px"
"100px 200em 300px".match(/\d+(?=px)/g);
// → ['100', '300']

// Найти число, после которого НЕ идёт "px"
"100px 200em 300px".match(/\d+(?!px)/g);
// → ['200']

// Найти сумму в рублях, перед которой идёт "price: "
"price: 1000₽, tax: 200₽".match(/(?<=price: )\d+/g);
// → ['1000']

// Валидация пароля: минимум 8 символов, есть буква и цифра
const passwordRegex = /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/;
passwordRegex.test("abc12345");   // true
passwordRegex.test("12345678");   // false (нет буквы)
passwordRegex.test("abc");        // false (короткий)

Флаги

Флаги модифицируют поведение регулярного выражения. В JavaScript они ставятся после закрывающего слеша: /pattern/gi.

ФлагЗначение
gGlobal — искать все совпадения, а не только первое
iCase-insensitive — игнорировать регистр
mMultiline — ^ и $ для каждой строки, а не только начала/конца текста
sSingle-line (dotall) — . совпадает и с переносом строки
uUnicode — корректная обработка Unicode-символов (включая кириллицу)
ySticky — поиск строго с позиции lastIndex

Флаг u особенно важен для работы с кириллицей. Без него\w не включает русские буквы, и шаблон /^\w+$/ не matches «Привет». С флагом u используйте \p{L} для любой буквы любого языка.

// Кириллическое слово (с флагом u)
/^\p{L}+$/u.test("Привет");  // true
/^\w+$/u.test("Привет");     // false (\w без u не понимает кириллицу)

// Поиск с игнорированием регистра
"Hello World".match(/world/i);  // → ['World']

// Multiline: ^ и $ для каждой строки
"line1\nline2\nline3".match(/^line\d/gm);
// → ['line1', 'line2', 'line3']  (без m было бы только 'line1')

Частые паттерны

Email

// Простая валидация email
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test("user@example.com");  // true

// Более строгая (RFC 5322 приближение)
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

URL

// Протокол + домен + путь
const urlRegex = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/;
urlRegex.test("https://example.com/path?q=1");  // true

IPv4

// IP-адрес версии 4
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
ipv4Regex.test("192.168.1.1");   // true
ipv4Regex.test("256.1.1.1");     // false

Дата в формате ISO

// YYYY-MM-DD
const dateRegex = /^\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])$/;
dateRegex.test("2025-04-09");  // true
dateRegex.test("2025-13-01");  // false (нет 13-го месяца)

Цвет в HEX

// #RGB или #RRGGBB
const hexRegex = /^#(?:[0-9a-fA-F]{3}){1,2}$/;
hexRegex.test("#fff");     // true
hexRegex.test("#a1b2c3");  // true
hexRegex.test("#12");      // false

JavaScript API

В JavaScript regex используется через методы строк и через объект RegExp. Основные методы: String.prototype.match — поиск первого или всех совпадений, String.prototype.test — проверка наличия,String.prototype.replace — замена, String.prototype.split— разбиение по шаблону, RegExp.prototype.exec — пошаговый поиск с извлечением групп.

// Проверка
/^\d+$/.test("12345");  // true

// Поиск всех совпадений
"one 1, two 2, three 3".match(/\d/g);  // ['1', '2', '3']

// Замена с использованием групп
"2025-04-09".replace(/(\d{4})-(\d{2})-(\d{2})/, "$3.$2.$1");
// → "09.04.2025"

// Именованные группы (ES2018+)
const m = "2025-04-09".match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);
m.groups.year;   // "2025"
m.groups.month;  // "04"
m.groups.day;    // "09"

// Разбиение по нескольким разделителям
"a, b; c|d".split(/[,;|]\s*/);  // ['a', 'b', 'c', 'd']

// Пошаговый поиск через exec
const regex = /\d+/g;
let match;
while ((match = regex.exec("one 1 two 22 three 333")) !== null) {
  console.log(match[0], "at", match.index);
}

Типичные ошибки

Жадные квантификаторы

Самая частая ошибка — забыть, что * и + жадные. При извлечении HTML-тегов /<.*>/ на строке<a>text</a> найдёт всю строку целиком, а не отдельные теги. Решение: ленивый квантификатор /<.*?>/ или негативный класс /<[^>]*>/.

Catastrophic backtracking

Некоторые комбинации вложенных квантификаторов приводят к экспоненциальному росту времени работы. Например, /(a+)+b/ на строке из 30 «a» без завершающей «b» будет парситься секунды или минуты. Это используется в ReDoS-атаках (Regular Expression Denial of Service). Решение: избегать вложенных квантификаторов с пересекающимися классами, использовать possessive quantifiers (если поддерживаются) или атомарные группы.

Неэкранированные спецсимволы

Точка . в regex означает «любой символ», но часто нужна как обычная точка — например, в IP-адресе или домене. Не забывайте экранировать:/192\\.168\\.1\\.1/, а не /192.168.1.1/ (последнее matches и «192x168x1x1»). Аналогично с +, *,?, (, ), [, ],{, }, ^, $, |,\\.

Игнорирование Unicode

Без флага u символы вне ASCII (включая кириллицу) обрабатываются некорректно. \w не включает русские буква, . может «разрезать» составной символ. Для работы с кириллицей всегда добавляйте флагu и используйте Unicode-свойства: \p{L} (любая буква),\p{Ll} (строчная), \p{Lu} (заглавная).

Тестирование и отладка

Regex трудно читать и легко ошибиться. Поэтому обязательно тестируйте — на примерах, которые должны совпадать, и на примерах, которые не должны. Удобные инструменты: regex101.com (с подробным разбором), regexr.com, нашregex-тестер. Они показывают совпадения в реальном времени, объясняют каждую часть шаблона, позволяют сохранять и делиться ссылками.

При отладке разбивайте сложный regexp на части. Сначала проверьте, что первая часть находит нужные фрагменты, потом добавьте следующую. Не пытайтесь сразу написать шаблон на 200 символов — он гарантированно будет с ошибками. Документируйте сложные regex-комментариями через (?#...) в языках, которые это поддерживают.

Когда НЕ использовать regex

Regex отлично подходит для поиска и замены по шаблону, но плохо — для парсинга иерархических структур. Не пытайтесь парсить HTML, XML, JSON регулярными выражениями — это путь к страданию и багам. HTML имеет вложенность, атрибуты, комментарии, сущности, и regex не умеет работать с вложенностью. Используйте специализированные парсеры: DOMParser для HTML в браузере, cheerio в Node.js, native JSON.parse для JSON, lxml или ElementTree для XML в Python.

Также regex избыточен для простых проверок. Если нужно проверить, что строка содержит подстроку — используйте includes(). Если нужно проверить начало — startsWith(). Если нужно простое равенство — обычное===. Regex включается тогда, когда шаблон действительно сложный и не выражается через простые строковые операции.

Производительность

Компиляция регулярного выражения занимает время. Если один и тот же regex используется много раз в цикле, вынесите его за пределы цикла и используйте флаг g с методом exec или test сlastIndex. В JavaScript для этого есть RegExp с флагомg и свойство lastIndex. Для сложных проверок можно использовать re2 — библиотеку Google, которая гарантирует линейное время выполнения и не подвержена catastrophic backtracking.

Заключение

Регулярные выражения — мощный инструмент, который окупает время на изучение. Базовый синтаксис (метасимволы, квантификаторы, классы) покрывает 80% задач. Продвинутые возможности (lookahead, lookbehind, именованные группы, флаги) добавляют ещё 15%. Оставшиеся 5% — это действительно сложные случаи, где лучше поискать готовое решение или написать полноценный парсер. Главное правило: не пытайтесь писать regex «вслепую» — всегда тестируйте в специальном инструменте. Используйте наш regex-тестер для экспериментов и проверки шаблонов перед использованием в коде.

Попробуйте эти инструменты

Похожие статьи