📖 Справочник по регулярным выражениям

Синтаксис, глобальная замена, группы и подстановки

📋 Содержание

1. Базовые метасимволы

Регулярные выражения — это шаблоны для поиска и манипуляции текстом. Метасимволы имеют специальное значение:

Символ Описание Пример Совпадение
. Любой символ (кроме перевода строки) a.c abc, axc, a c
\ Экранирование метасимволов \. буквальный символ «.»
| Альтернация (ИЛИ) cat|dog cat или dog
Метасимволы . * + ? [ ] ( ) { } ^ $ | \ имеют специальное значение. Для их буквального поиска используйте обратный слэш: \., \*, \+ и т.д.

2. Якоря и границы

Якоря не совпадают с символами, а указывают на позицию в строке:

Символ Описание Пример
^ Начало строки (или начала в многострочном режиме) ^Hello — «Hello» в начале
$ Конец строки end$ — «end» в конце
\b Граница слова \bword\b — слово «word» целиком
\B Не граница слова \Bing\B — «ing» внутри слова
\A Абсолютное начало текста \AStart
\Z Абсолютный конец текста End\Z
Входной текст: Hello world! hello everyone. Паттерн: ^hello (с флагом i) Не найдёт (т.к. начало строки — «H», а не «h» без флага i) Паттерн: ^Hello Результат: ✓ «Hello» в позиции 0

3. Классы символов

Символ Описание Эквивалент
\d Цифра [0-9]
\D Не цифра [^0-9]
\w Буквенный символ, цифра или подчёркивание [a-zA-Z0-9_]
\W Не буквенный символ [^a-zA-Z0-9_]
\s Пробельный символ [ \t\n\r\f\v]
\S Не пробельный символ [^ \t\n\r\f\v]

Пользовательские классы символов

Синтаксис Описание Пример
[abc] Любой из перечисленных символов [aeiou] — гласные
[^abc] Любой символ, кроме перечисленных [^0-9] — не цифры
[a-z] Диапазон символов [a-zA-Z] — все латинские буквы
// Найти все слова, начинающиеся с заглавной буквы
[A-Z][a-z]+

// Валидация HEX-цвета
#[0-9a-fA-F]{6}

// Найти гласные в тексте
[аеёиоуыэюяАЕЁИОУЫЭЮЯ]

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

Определяют, сколько раз символ или группа могут повторяться:

Квантификатор Значение Пример Совпадёт
* 0 или более раз ab*c ac, abc, abbc, abbbc
+ 1 или более раз ab+c abc, abbc, abbbc (но не ac)
? 0 или 1 раз colou?r color, colour
{n} Ровно n раз a{3} aaa
{n,} Не менее n раз a{2,} aa, aaa, aaaa...
{n,m} От n до m раз a{2,4} aa, aaa, aaaa

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

По умолчанию квантификаторы жадные — захватывают максимально возможное совпадение. Добавив ?, делаем их ленивыми:

Жадный: <.*>

Вход: <b>text</b>

Захватит: <b>text</b> (всё целиком)

Ленивый: <.*?>

Вход: <b>text</b>

Захватит: <b> и </b> (по отдельности)

5. Альтернация (ИЛИ)

Оператор | позволяет задать несколько вариантов:

// Совпадение: Mon, Tue, Wed, Thu, Fri
Mon|Tue|Wed|Thu|Fri

// Использование с группами
(I love|I hate) (cats|dogs)
// Совпадёт: "I love cats", "I love dogs", "I hate cats", "I hate dogs"
Альтернация имеет самый низкий приоритет. Используйте круглые скобки для группировки: (Mon|Tue|Wed) вместо Mon|Tue|Wed, когда нужно ограничить область действия.

6. Группы и захват

Группы позволяют извлекать части совпадения и использовать их в замене:

Синтаксис Тип Описание
(...) Захватывающая Сохраняет совпадение в группу с номером
(?<name>...) Именованная Сохраняет совпадение в именованную группу
(?:...) Незахватывающая Группирует, но НЕ сохраняет
// Захватывающие группы
(\d{2})\.(\d{2})\.(\d{4})
// Группа 1: день, Группа 2: месяц, Группа 3: год

// Именованные группы
(?<day>\d{2})\.(?<month>\d{2})\.(?<year>\d{4})

// Незахватывающая группа (для квантификатора или альтернации)
(?:https?|ftp)://[^\s]+

Нумерация групп

Группы нумеруются по открывающим скобкам слева направо:

 ((a)(b)c)(d)
  │ │ │ │   │
  │ │ │ │   └─ группа 4: "d"
  │ │ │ └───── группа 3: "b"
  │ │ └─────── группа 2: "ab"
  │ └───────── группа 1: "abc"
  └─────────── группа 0 (всё совпадение): "abcd"

7. Lookaround (опережающие/ретроспективные проверки)

Проверяют окружение совпадения, не включая его в результат:

Синтаксис Название Описание
(?=...) Positive Lookahead Совпадение, если ЗА ним следует ...
(?!...) Negative Lookahead Совпадение, если ЗА ним НЕ следует ...
(?<=...) Positive Lookbehind Совпадение, если ПЕРЕД ним стоит ...
(?<!...) Negative Lookbehind Совпадение, если ПЕРЕД ним НЕ стоит ...
Паттерн: \d+(?=px) Текст: «16px font, 2em margin, 100px width» Результат: найдёт «16» и «100» (числа перед «px»)
Паттерн: (?<=@)\w+ Текст: «email @username and @admin» Результат: найдёт «username» и «admin» (имена после «@»)

8. Флаги регулярных выражений

Флаг Название Описание
g Global Поиск всех совпадений (а не только первого)
i Case-insensitive Без учёта регистра
m Multiline ^ и $ совпадают с началом/концом каждой строки
s Dotall . совпадает с переводом строки
u Unicode Полная поддержка Unicode

9. Синтаксис замены (Replacement)

При замене текста с помощью регулярных выражений в строке замены можно использовать специальные конструкции:

Конструкция Описание Пример
$1, $2, ... Ссылка на захваченную группу по номеру $1-$2
$& Всё совпадение целиком [$&]
$` Часть строки до совпадения
$' Часть строки после совпадения
$0 Всё совпадение (в некоторых движках) $0!
${name} Ссылка на именованную группу ${day}.${month}
\1, \2, ... Обратная ссылка (в некоторых языках — замена) \1 → \2
В JavaScript используются $1, $&. В sed/grep (POSIX) — \1. В Python re.sub\1 или \g<1>. В Sublime Text / VSCode$1.

10. Глобальная замена

Глобальная замена означает применение замены ко всем найденным совпадениям в тексте, а не только к первому. Для этого используется флаг g (global).

В JavaScript

const text = "foo bar foo baz foo";

// Без флага g — заменится только первое совпадение
text.replace(/foo/, "XXX");
// → "XXX bar foo baz foo"

// С флагом g — заменяются ВСЕ совпадения
text.replace(/foo/g, "XXX");
// → "XXX bar XXX baz XXX"

В Python

import re

text = "foo bar foo baz foo"

# По умолчанию re.sub заменяет ВСЕ (count=0)
re.sub(r'foo', 'XXX', text)
# → "XXX bar XXX baz XXX"

# Ограничить количество замен
re.sub(r'foo', 'XXX', text, count=2)
# → "XXX bar XXX baz foo"

В sed (Unix)

# Без g — только первое совпадение в строке
sed 's/foo/XXX/' file.txt

# С флагом g — все совпадения в каждой строке
sed 's/foo/XXX/g' file.txt

В VS Code (поиск и замена)

1. Ctrl+H — открыть панель замены
2. Нажать кнопку .* (Use Regular Expression)
3. Кнопка «Replace All» (Ctrl+Alt+Enter) — глобальная замена

Find:    (\w+)\s*=\s*([^;]+);
Replace: let $1 = $2;
Важно: При глобальной замене будьте осторожны с жадными квантификаторами. Паттерн .+ может «съесть» всю строку и произвести только одну замену. Используйте .+? (ленивый) или конкретные классы символов.

11. Использование групп для подстановки

Это одна из самых мощных возможностей: захватить части текста и переупорядочить или модифицировать их при замене.

Пример 1: Преобразование формата даты

Паттерн: (\d{2})\.(\d{2})\.(\d{4}) Текст: «Дата рождения: 15.03.1990» Замена: $3-$2-$1 Результат: «Дата рождения: 1990-03-15»
// JavaScript
"15.03.1990".replace(
  /(\d{2})\.(\d{2})\.(\d{4})/g,
  '$3-$2-$1'
);
// → "1990-03-15"

Пример 2: Обмен местами имени и фамилии

Паттерн: (\w+)\s+(\w+) Текст: «Иван Петров, Анна Сидорова» Замена: $2, $1 Результат: «Петров, Иван, Сидорова, Анна»
const names = "Иван Петров, Анна Сидорова";
names.replace(/(\p{L}+)\s+(\p{L}+)/gu, '$2, $1');
// → "Петров, Иван, Сидорова, Анна"
// Флаг u + \p{L} для работы с Unicode буквами

Пример 3: Обрамление найденных слов

Паттерн: \b(важно|внимание)\b Текст: «Это важно: обратите внимание на детали» Замена: <mark>$</mark> Результат: «Это <mark>важно</mark>: обратите <mark>внимание</mark> на детали»
text.replace(/\b(важно|внимание)\b/gi, '<mark>$&</mark>');
// $& — всё совпадение целиком

Пример 4: Именованные группы

// Паттерн с именованными группами
const pattern = /(?<day>\d{2})\.(?<month>\d{2})\.(?<year>\d{4})/g;

"15.03.1990".replace(pattern, '${year}-${month}-${day}');
// → "1990-03-15"
# Python — использование именованных групп
import re

text = "15.03.1990"
pattern = r'(?P<day>\d{2})\.(?P<month>\d{2})\.(?P<year>\d{4})'

re.sub(pattern, r'\g<year>-\g<month>-\g<day>', text)
# → "1990-03-15"

Пример 5: Функция как строка замены (JavaScript)

Для сложных преобразований можно передать функцию:

const text = "border: 16px; margin: 2em; width: 100px";

// Конвертировать px в rem (при базе 16px)
text.replace(/(\d+)px/g, (match, number) => {
    return (parseInt(number) / 16) + 'rem';
});
// → "border: 1rem; margin: 2em; width: 6.25rem"

12. Практические примеры глобальной замены с группами

🔗 Преобразование ссылок

Паттерн:

(https?://[^\s]+)

Замена:

<a href="$1">$1</a>

Результат: URL становятся кликабельными ссылками

📱 Форматирование телефона

Паттерн:

(\d{3})(\d{3})(\d{2})(\d{2})

Замена:

+7 ($1) $2-$3-$4

Было: 9001234567
Стало: +7 (900) 123-45-67

🐍 camelCase → snake_case

Паттерн:

([A-Z])([a-z]*)

Замена:

_$1$2 (с .toLowerCase())

Было: getUserName
Стало: get_user_name

🔄 Изменение порядка слов

Паттерн:

"([^"]+)"\s*:\s*"([^"]+)"

Замена:

$2 = "$1"

Преобразование JSON-ключей в переменные

📝 Markdown → HTML (bold)

Паттерн:

\*\*([^*]+)\*\*

Замена:

<strong>$1</strong>

Было: **жирный текст**
Стало: <strong>жирный текст</strong>

🧹 Удаление лишних пробелов

Паттерн:

[ \t]+

Замена:

 (один пробел)

Множественные пробелы/табы → один пробел

Полный пример: обработка CSV-данных

// Исходные данные
const csv = `
Иванов, Иван, 25, Москва
Петров, Пётр, 30, Санкт-Петербург
Сидорова, Анна, 28, Казань
`;

// Преобразование в HTML-таблицу
const html = csv
    .trim()
    .replace(
        /^(.+),(.+),(.+),(.+)$/gm,
        '<tr><td>$1</td><td>$2</td><td>$3</td><td>$4</td></tr>'
    );
// Флаги: g — глобально, m — многострочный (^ и $ для каждой строки)

Пример: переименование файлов массово

# Переименование файлов вида "photo_2024_03_15.jpg" → "2024-03-15_photo.jpg"
# Используем find + sed или rename

# Bash с использованием sed:
for file in photo_*.jpg; do
    new_name=$(echo "$file" | sed 's/photo_\([0-9]\{4\}\)_\([0-9]\{2\}\)_\([0-9]\{2\}\)/\1-\2-\3_photo/')
    mv "$file" "$new_name"
done

📌 Шпаргалка по популярным паттернам

Задача Паттерн Замена Флаги
Email (простой) [\w.-]+@[\w.-]+\.\w{2,} <a href="mailto:$&">$&</a> g
Дата ДД.ММ.ГГГГ → ГГГГ-ММ-ДД (\d{2})\.(\d{2})\.(\d{4}) $3-$2-$1 g
Удаление HTML-тегов <[^>]+> (пусто) g
Лишние пробелы \s{2,} (пробел) g
Перенос строки → <br> \n <br>\n g
Слова с заглавной в кавычки \b([A-ZА-Я]\w*)\b "$1" g
camelCase → kebab-case ([a-z])([A-Z]) $1-$2 g + toLowerCase
Извлечение числа из строки (\d+[\d.,]*) $1 (захват) g