Замены через s/// и захваты через ()

В прошлом уроке мы научились искать совпадения по шаблону. Но регулярки умеют и больше — заменять найденный текст на другой. Это одна из самых частых задач в реальной работе: почистить лишние пробелы, поменять формат даты, скрыть часть номера карты звёздочками. Для этого в Perl есть оператор замены s///.

Оператор s///

Буква s означает substitute, «заменить». Синтаксис такой: s/шаблон/замена/. Слэши здесь разделяют три части оператора на две секции: что искать и на что менять. Оператор применяется через уже знакомый нам =~.

my $greeting = "Привет, Мир!";

$greeting =~ s/Мир/Perl/;

print "$greeting\n";

Вывод:

Привет, Perl!

Здесь мы ищем в переменной $greeting слово «Мир» и заменяем его на «Perl». Важная деталь: оператор s/// изменяет саму переменную $greeting — это происходит «на месте», в отличие от многих других языков, где обычно приходится создавать новую строку. Именно поэтому слева от =~ должна стоять переменная, а не просто текстовое значение.

По умолчанию s/// заменяет только первое найденное совпадение. Если в строке слово встречается несколько раз, а поменять нужно все — понадобится флаг g, который мы разберём в следующем уроке.

Группы захвата: скобки как «карманы»

Самое мощное в регулярках — это группы захвата. Если часть шаблона обернуть в круглые скобки, Perl запоминает, что именно туда попало, и кладёт это в специальные переменные $1, $2, $3 и так далее — по порядку скобок слева направо.

my $date = "25-12-2026";

if ($date =~ /(\d{2})-(\d{2})-(\d{4})/) {
    print "День: $1\n";
    print "Месяц: $2\n";
    print "Год: $3\n";
}

Вывод:

День: 25
Месяц: 12
Год: 2026

Разберём шаблон (\d{2})-(\d{2})-(\d{4}). Первая пара скобок ловит две цифры (день), потом идёт литеральный дефис, вторая пара скобок ловит ещё две цифры (месяц), снова дефис, и третья пара скобок ловит четыре цифры (год). После успешного совпадения переменная $1 хранит содержимое первой группы, $2 — второй, $3 — третьей. Эти переменные живут до следующего совпадения, так что пользоваться ими нужно сразу после проверки.

Использование захватов в замене

Самая полезная комбинация — использовать группы захвата не только при поиске, но и в самой строке замены. Например, чтобы поменять формат даты с «день-месяц-год» на «год/месяц/день»:

my $date = "25-12-2026";

$date =~ s/(\d{2})-(\d{2})-(\d{4})/$3\/$2\/$1/;

print "$date\n";

Вывод:

2026/12/25

Здесь в части «на что менять» мы используем $1, $2, $3 — то, что было захвачено при поиске. Обратите внимание: слэш внутри замены пришлось экранировать как \/, потому что обычный слэш — это разделитель частей оператора s///, и Perl мог бы принять его за конец шаблона.

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

Мини-пример: маскировка номера карты

Соберём то, что узнали, в практическую задачу — скрыть все цифры номера банковской карты, кроме последних четырёх:

my $card = "4276 1234 5678 9012";

$card =~ s/(\d{4} \d{4} \d{4}) (\d{4})/**** **** **** $2/;

print "$card\n";

Вывод:

**** **** **** 9012

Первая группа захватывает первые три блока цифр целиком (но мы её даже не используем в замене — просто «поглощаем» ненужную часть), а вторая группа сохраняет последний блок, чтобы вставить его обратно через $2. Остальную часть заменяем на звёздочки прямо текстом.

Частые ошибки

Частая ошибка — забыть, что $1, $2 и так далее «живут» только после успешного совпадения. Если проверка совпадения провалилась (например, внутри if, который не выполнился), то использование $1 дальше в коде вернёт мусор или значение от предыдущего совпадения — это может привести к незаметным багам.

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

И третья — забывать, что s/// без специального флага меняет только первое вхождение. Если ожидалось, что заменятся все повторения слова в тексте, а поменялось только одно — дело именно в этом, и решение уже совсем рядом, в следующем уроке.

Итоги

Оператор s/шаблон/замена/ ищет совпадение по шаблону и заменяет его прямо в переменной. Круглые скобки в шаблоне создают группы захвата, доступные потом как $1, $2, $3 — и их можно использовать не только для чтения найденного текста, но и прямо внутри замены, чтобы переставлять части строки местами. Это основа для любой более сложной обработки текста в Perl.

Проверьте себя
1. Что делает оператор s/шаблон/замена/ в Perl?
AТолько проверяет, есть ли совпадение
BИщёт совпадение по шаблону и заменяет его в переменной
CРазбивает строку на массив по шаблону
DВыводит все совпадения на экран
2. Как обратиться к тексту, захваченному первой парой скобок в шаблоне?
A$0
B$first
C$1
D#1