Синтаксис, глобальная замена, группы и подстановки
Регулярные выражения — это шаблоны для поиска и манипуляции текстом. Метасимволы имеют специальное значение:
| Символ | Описание | Пример | Совпадение |
|---|---|---|---|
. |
Любой символ (кроме перевода строки) | a.c |
abc, axc, a c |
\ |
Экранирование метасимволов | \. |
буквальный символ «.» |
| |
Альтернация (ИЛИ) | cat|dog |
cat или dog |
. * + ? [ ] ( ) { } ^ $ | \ имеют специальное значение. Для их буквального поиска используйте обратный слэш: \., \*, \+ и т.д.
Якоря не совпадают с символами, а указывают на позицию в строке:
| Символ | Описание | Пример |
|---|---|---|
^ |
Начало строки (или начала в многострочном режиме) | ^Hello — «Hello» в начале |
$ |
Конец строки | end$ — «end» в конце |
\b |
Граница слова | \bword\b — слово «word» целиком |
\B |
Не граница слова | \Bing\B — «ing» внутри слова |
\A |
Абсолютное начало текста | \AStart |
\Z |
Абсолютный конец текста | End\Z |
^hello (с флагом i)
Не найдёт (т.к. начало строки — «H», а не «h» без флага i)
Паттерн: ^Hello
Результат: ✓ «Hello» в позиции 0
| Символ | Описание | Эквивалент |
|---|---|---|
\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}
// Найти гласные в тексте
[аеёиоуыэюяАЕЁИОУЫЭЮЯ]
Определяют, сколько раз символ или группа могут повторяться:
| Квантификатор | Значение | Пример | Совпадёт |
|---|---|---|---|
* |
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 |
По умолчанию квантификаторы жадные — захватывают максимально возможное совпадение. Добавив ?, делаем их ленивыми:
<.*>Вход: <b>text</b>
Захватит: <b>text</b> (всё целиком)
<.*?>Вход: <b>text</b>
Захватит: <b> и </b> (по отдельности)
Оператор | позволяет задать несколько вариантов:
// Совпадение: 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, когда нужно ограничить область действия.
Группы позволяют извлекать части совпадения и использовать их в замене:
| Синтаксис | Тип | Описание |
|---|---|---|
(...) |
Захватывающая | Сохраняет совпадение в группу с номером |
(?<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"
Проверяют окружение совпадения, не включая его в результат:
| Синтаксис | Название | Описание |
|---|---|---|
(?=...) |
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» (имена после «@»)
| Флаг | Название | Описание |
|---|---|---|
g |
Global | Поиск всех совпадений (а не только первого) |
i |
Case-insensitive | Без учёта регистра |
m |
Multiline | ^ и $ совпадают с началом/концом каждой строки |
s |
Dotall | . совпадает с переводом строки |
u |
Unicode | Полная поддержка Unicode |
При замене текста с помощью регулярных выражений в строке замены можно использовать специальные конструкции:
| Конструкция | Описание | Пример |
|---|---|---|
$1, $2, ... |
Ссылка на захваченную группу по номеру | $1-$2 |
$& |
Всё совпадение целиком | [$&] |
$` |
Часть строки до совпадения | — |
$' |
Часть строки после совпадения | — |
$0 |
Всё совпадение (в некоторых движках) | $0! |
${name} |
Ссылка на именованную группу | ${day}.${month} |
\1, \2, ... |
Обратная ссылка (в некоторых языках — замена) | \1 → \2 |
$1, $&. В sed/grep (POSIX) — \1. В Python re.sub — \1 или \g<1>. В Sublime Text / VSCode — $1.
Глобальная замена означает применение замены ко всем найденным совпадениям в тексте, а не только к первому. Для этого используется флаг g (global).
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"
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"
# Без g — только первое совпадение в строке
sed 's/foo/XXX/' file.txt
# С флагом g — все совпадения в каждой строке
sed 's/foo/XXX/g' file.txt
1. Ctrl+H — открыть панель замены
2. Нажать кнопку .* (Use Regular Expression)
3. Кнопка «Replace All» (Ctrl+Alt+Enter) — глобальная замена
Find: (\w+)\s*=\s*([^;]+);
Replace: let $1 = $2;
.+ может «съесть» всю строку и произвести только одну замену. Используйте .+? (ленивый) или конкретные классы символов.
Это одна из самых мощных возможностей: захватить части текста и переупорядочить или модифицировать их при замене.
(\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"
(\w+)\s+(\w+)
Текст: «Иван Петров, Анна Сидорова»
Замена: $2, $1
Результат: «Петров, Иван, Сидорова, Анна»
const names = "Иван Петров, Анна Сидорова";
names.replace(/(\p{L}+)\s+(\p{L}+)/gu, '$2, $1');
// → "Петров, Иван, Сидорова, Анна"
// Флаг u + \p{L} для работы с Unicode буквами
\b(важно|внимание)\b
Текст: «Это важно: обратите внимание на детали»
Замена: <mark>$</mark>
Результат: «Это <mark>важно</mark>: обратите <mark>внимание</mark> на детали»
text.replace(/\b(важно|внимание)\b/gi, '<mark>$&</mark>');
// $& — всё совпадение целиком
// Паттерн с именованными группами
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"
Для сложных преобразований можно передать функцию:
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"
Паттерн:
(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
Паттерн:
([A-Z])([a-z]*)
Замена:
_$1$2 (с .toLowerCase())
Было: getUserName
Стало: get_user_name
Паттерн:
"([^"]+)"\s*:\s*"([^"]+)"
Замена:
$2 = "$1"
Преобразование JSON-ключей в переменные
Паттерн:
\*\*([^*]+)\*\*
Замена:
<strong>$1</strong>
Было: **жирный текст**
Стало: <strong>жирный текст</strong>
Паттерн:
[ \t]+
Замена:
(один пробел)
Множественные пробелы/табы → один пробел
// Исходные данные
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 |