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

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

У меня есть файл на несколько тысяч строк. В одних местах стоят двойные пробелы, между абзацами накопились пустые строки, даты записаны как 11.08.2026, а список людей нужно перестроить из «Иван Петров» в «Петров Иван». Править такой документ вручную незачем. Включаю режим регулярных выражений в поиске, описываю нужный фрагмент и меняю все подходящие места одной командой.

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

Главная идея проста. Обычный поиск знает конкретный текст, а regex описывает его структуру. Можно искать не число 2026, а «любую последовательность цифр», не конкретные три пробела, а «два и больше пробелов», не отдельную дату, а «две цифры, точка, две цифры, точка, четыре цифры». Захватывающие группы позволяют сохранить найденные части, а затем собрать их в другом порядке.

Такой подход особенно полезен редакторам, SEO-специалистам, контент-менеджерам и всем, кто работает с большими текстами, CSV, логами, Markdown или исходным HTML. Я буду использовать синтаксис, близкий к поиску внутри Visual Studio Code. Официальная документация VS Code подтверждает работу захватывающих групп и ссылок $1, $2 в поле замены. Значения основных конструкций вроде d, s, ., групп и границ можно сверить со справочником MDN. В других редакторах синтаксис отдельных конструкций и строки замены может отличаться.

Что на самом деле делает regex при замене

Допустим, я ищу

[0-9]+

Плюс относится к предыдущему элементу и требует один или больше повторов, поэтому выражение найдет 7, 42, 2026 и 150000. Если вместо конкретного числа в документе встречаются сотни разных значений, один шаблон охватывает их все.

Шаблон Что ищет
[0-9] одну цифру от 0 до 9
[0-9]+ одну или несколько цифр подряд
. один произвольный символ, обычно кроме перевода строки
* ноль или больше повторов предыдущего элемента
+ один или больше повторов
{2,} два или больше повторов
^ начало строки или входной строки в зависимости от режима
$ конец строки или входной строки в зависимости от режима
(...) захватывающую группу

Точка в регулярном выражении не означает обычную точку. Для буквального символа точки пишут .. По той же причине специальные символы нельзя механически вставлять в выражение и ожидать буквального поиска.

Есть еще одна ловушка. s означает не просто пробел. В JavaScript-подобных регулярных выражениях класс включает переводы строк, табуляцию и другие пробельные символы. Поэтому выражение s+ опасно применять для бездумной «чистки пробелов». Глобальная замена может заодно уничтожить разметку абзацев.

Шесть операций, которые я действительно использую

1. Убираю двойные и тройные пробелы

Для обычных пробелов безопаснее явно указать символ, который хочу сжать.

Поиск

[ ]{2,}

Замена

 

Шаблон заменит два, три или двадцать обычных пробелов одним. Я намеренно не использую здесь s+, потому что задача касается пробелов, а не всех пробельных символов.

Если документ содержит табуляцию, неразрывные пробелы или отступы в коде, универсальная массовая чистка уже требует осторожности. Например, выражение [ t]+ способно сломать отступы в исходниках.

2. Удаляю пробелы в конце строк

Невидимые пробелы после последнего символа часто приезжают из таблиц, CMS и копирования текста.

Поиск

[ t]+$

Замена остается пустой.

Выражение находит пробелы и табуляцию непосредственно перед концом строки. Для обычного текста такая операция обычно полезнее, чем попытка нормализовать все пробельные символы сразу.

3. Удаляю пустые строки

Если редактор обрабатывает ^ как начало каждой строки, можно найти строки, которые содержат только пробелы или табуляцию.

Поиск

^[ t]*r?

Замена остается пустой.

[ t]* допускает пустую строку или строку только с пробелами. r?
учитывает распространенные варианты перевода строки. Такой шаблон удаляет пустые строки полностью, поэтому для обычной статьи я сначала смотрю список совпадений. Иногда пустая строка специально разделяет абзацы и удалять ее нельзя.

Если нужно лишь сократить большие провалы между абзацами, задача другая. Например, три и больше переводов строки можно заменить двумя, сохранив визуальную границу между абзацами.

(r?
){3,}

4. Ищу строки определенного типа

Представим выгрузку, где меня интересуют только строки, начинающиеся со слова «Цена» и содержащие число.

^Цена[ t]+[0-9]+[^r
]*$

Шаблон найдет такие строки

Цена 1200 рублей
 Цена 7990 ₽
 Цена 45000 со скидкой

Здесь я специально использовал [^r
]*
вместо привычного .*. Выражение прямо говорит, что после числа разрешены любые символы, кроме перевода строки. Чем точнее описан допустимый текст, тем меньше шанс случайно захватить лишний фрагмент.

5. Переставляю имя и фамилию

Есть простой список

Иван Петров
 Мария Соколова
 Алексей Смирнов

Нужно получить фамилию перед именем.

Поиск

^(S+)[ t]+(S+)$

Замена в VS Code

$2 $1

Круглые скобки создают две захватывающие группы. Для строки Иван Петров первая группа содержит Иван, вторая содержит Петров. В поле замены я обращаюсь к группам в обратном порядке.

Петров Иван
 Соколова Мария
 Смирнов Алексей

Такой шаблон работает не с «именами» как смысловой сущностью, а с двумя непробельными полями. Строки «Анна Мария Петрова», «Людвиг ван Бетховен» или ФИО с дополнительными колонками требуют другого правила. Регулярное выражение видит структуру символов, а не понимает человеческие имена.

6. Меняю формат даты

В исходном документе встречается дата

11.08.2026

а система требует

2026-08-11

Поиск

b([0-9]{2}).([0-9]{2}).([0-9]{4})b

Замена

$3-$2-$1

Первая группа содержит день, вторая месяц, третья год. Меняя порядок групп, получаем новый формат без разбора каждой даты вручную.

Но регулярка здесь проверяет только форму записи. Строка 39.19.2026 тоже состоит из двух цифр, двух цифр и четырех цифр. Можно усложнить шаблон и ограничить месяц диапазоном от 01 до 12, а день от 01 до 31, но даже такой regex не узнает, что 31 апреля не существует и что правила для 29 февраля зависят от года. Если программе нужна настоящая проверка календарной даты, я использую парсер дат, а регулярному выражению оставляю поиск и преобразование формата.

Зачем нужны $1 и $2 при массовой замене

Захватывающие группы полезны не потому, что позволяют найти текст. Главная сила проявляется при перестройке найденного фрагмента.

Допустим, в документе сотни строк вида

Статья №314 опубликована
 Статья №582 опубликована
 Статья №901 опубликована

Я хочу получить

Опубликована статья 314
 Опубликована статья 582
 Опубликована статья 901

Поиск

Статья №([0-9]+) опубликована

Замена

Опубликована статья $1

Редактор находит каждую фразу независимо, сохраняет номер в первой группе и вставляет найденное значение на новое место. Команда «Заменить все» обработает документ целиком.

Полезно различать две похожие записи. Внутри самого регулярного выражения 1 обычно означает ссылку на уже найденную первую группу и позволяет искать повтор того же текста. В поле замены VS Code использует $1 для вставки содержимого первой группы. Другие движки могут применять иной синтаксис, поэтому переносить сложную замену между программами без проверки не стоит.

Есть еще одна неочевидная проблема с привычным w. Многие воспринимают конструкцию как «любая буква». В JavaScript w в базовом режиме ориентирован прежде всего на латинские буквы, цифры и знак подчеркивания. Поэтому шаблон вроде w+ не следует автоматически использовать для русских имен. В примере выше я выбрал S+, поскольку задача состоит в поиске двух полей без пробелов, а не в определении того, какие символы считать буквами.

Где массовая замена начинает вредить

Самая опасная кнопка в работе с regex называется «Заменить все». Ошибка в одном символе способна изменить сотни строк вполне корректно с точки зрения регулярного выражения, но совершенно неправильно с точки зрения данных.

Я придерживаюсь простой последовательности. Сначала запускаю поиск без замены и смотрю несколько совпадений из разных частей документа. Затем заменяю один фрагмент. Только после проверки применяю операцию ко всему файлу. Для важного документа сохраняю исходную копию или работаю там, где можно надежно отменить изменения.

Чаще всего проблемы возникают из-за слишком широких выражений. .* выглядит удобно, но говорит движку разрешить почти любые символы в максимально широком диапазоне, который допускают остальные части шаблона. Если структура текста известна, я предпочитаю точный класс вроде [0-9]+, [ t]+ или [^r
]*
.

С HTML действует тот же принцип. Regex хорошо подходит для узкой механической правки предсказуемого текста, например для замены одинакового атрибута в контролируемом наборе строк. Но попытка разбирать произвольную HTML-структуру одним большим выражением быстро становится хрупкой. Вложенные элементы, переносы строк, другой порядок атрибутов, комментарии и содержимое <script> легко ломают шаблон. Для структурного преобразования HTML надежнее работать с DOM или HTML-парсером.

Еще одна типичная ошибка заключается в попытке превратить regex в валидатор всего подряд. Регулярка прекрасно отвечает на вопрос «похожа ли строка на нужный формат», но гораздо хуже отвечает на вопрос «имеют ли данные реальный смысл». Проверить формат даты можно шаблоном. Проверить существование календарной даты лучше кодом. Найти похожий на email текст можно шаблоном. Проверить существование почтового ящика одной регуляркой невозможно.

Для редактора или SEO-специалиста не нужно учить сотни конструкций. Практическую пользу уже дают классы символов, квантификаторы, начало и конец строки, экранирование, круглые скобки и ссылки $1, $2. Такой набор закрывает очистку текста, преобразование дат, перестановку колонок, изменение шаблонных фраз и массу рутинных правок.

Я бы начинал именно с поиска и замены, а не с попыток написать сложную регулярку с первого раза. Найдите нужный фрагмент, постепенно сузьте шаблон, вынесите изменяющиеся части в группы, проверьте несколько совпадений и только потом запускайте массовую замену. Regex особенно хорош там, где текст повторяет понятную структуру. Чем хаотичнее данные и чем больше в задаче смысла, а не формы, тем быстрее стоит переходить от регулярных выражений к нормальному парсеру или программному коду.

Alt text
Обращаем внимание, что все материалы в этом блоге представляют личное мнение их авторов. Редакция SecurityLab.ru не несет ответственности за точность, полноту и достоверность опубликованных данных. Вся информация предоставлена «как есть» и может не соответствовать официальной позиции компании.
АНТИПОВ
0 : 1
ПРАВДА VS НАГЛОСТЬ
ПРАВ
Быть правым —
самый бесполезный актив
Умные проигрывают наглым. Логика сливается инстинктам толпы. Статусу и бюджетам плевать на ваши факты.
АНТИПОВ РЕЖЕТ БЕЗ НАРКОЗА
реклама