Флаги регулярных выражений: g, i, m
В предыдущих уроках мы видели, что операторы m// и s/// по умолчанию ведут себя довольно скромно: находят только первое совпадение и различают регистр букв. Флаги — это буквы, которые ставятся сразу после закрывающего слэша шаблона и меняют это поведение. Разберём три самых важных: g, i и m.
Флаг g: глобальный поиск
Буква g означает global. Без этого флага замена s/// останавливается после первого найденного совпадения. С флагом g она находит и заменяет вообще все вхождения в строке.
my $text = "кот сидит, кот спит, кот играет";
my $count = ($text =~ s/кот/пёс/g);
print "$text\n";
print "Заменено раз: $count\n";Вывод:
пёс сидит, пёс спит, пёс играет
Заменено раз: 3Обратите внимание на вторую строку: оператор s/// с флагом g возвращает не просто «истина/ложь», а количество сделанных замен. Это удобно, когда нужно не только поменять текст, но и узнать, сколько раз замена сработала — например, для подсчёта статистики или проверки, что заменилось хоть что-то.
Флаг g работает и с оператором поиска m//, но там его поведение чуть более тонкое: в списковом контексте он возвращает сразу все найденные совпадения массивом.
my $text = "Заказ 102, заказ 58, заказ 700";
my @numbers = $text =~ /(\d+)/g;
print "Найдено номеров: @numbers\n";Вывод:
Найдено номеров: 102 58 700Здесь (\d+)/g означает «найди все последовательности цифр по всей строке и верни их списком». Без флага g мы получили бы только «102» — первое совпадение — а флаг заставляет регулярку продолжать поиск до самого конца строки.
Флаг i: не важен регистр
Буква i означает insensitive, «нечувствительный» — а именно нечувствительный к регистру букв. Без этого флага заглавные и строчные буквы считаются разными символами.
my @words = ("Perl", "PERL", "perl", "PeRl");
foreach my $word (@words) {
if ($word =~ /^perl$/i) {
print "$word — совпадает\n";
}
}Вывод:
Perl — совпадает
PERL — совпадает
perl — совпадает
PeRl — совпадаетБез флага i шаблон /^perl$/ совпал бы только со строкой «perl» в нижнем регистре — а «Perl» или «PERL» бы уже не подошли. Флаг i убирает эту чувствительность полностью, и любая комбинация заглавных и строчных букв засчитывается как совпадение.
Кстати, в этом примере появились ещё два новых символа: ^ означает «начало строки», а $ — «конец строки». Вместе ^perl$ означает «вся строка целиком состоит ровно из слова perl», а не просто «где-то внутри встречается perl».
Флаг m: построчный режим
Буква m означает multiline, «многострочный». Он меняет, как символы ^ и $ ведут себя, если строка на самом деле содержит несколько строк текста, разделённых переносами \n.
Без флага m символы ^ и $ относятся только к самому началу и самому концу всей строки целиком. С флагом m они начинают работать после каждого переноса строки — то есть означают «начало любой строки» и «конец любой строки» внутри текста.
my $log = "OK: старт сервера\nОШИБКА: нет подключения\nOK: сервер работает";
my @errors = $log =~ /^ОШИБКА:.*$/mg;
print "Найдено строк с ошибкой: " . scalar(@errors) . "\n";
print "$errors[0]\n";Вывод:
Найдено строк с ошибкой: 1
ОШИБКА: нет подключенияЗдесь переменная $log — это на самом деле три строки текста, склеенные через \n. Флаг m позволяет шаблону ^ОШИБКА:.*$ сработать не только в самом начале всего текста, а на начале каждой отдельной строки внутри него. Флаг g здесь тоже нужен — без него мы бы нашли только первую подходящую строку и остановились, даже если ошибок было несколько.
Комбинирование флагов
Флаги можно (и часто нужно) комбинировать — они просто пишутся подряд одной группой букв после шаблона, в любом порядке:
my $text = "perl отлично\nPERL — язык текста\nPyThOn — не он";
my @lines = $text =~ /^perl.*$/mig;
foreach my $line (@lines) {
print "$line\n";
}Вывод:
perl отлично
PERL — язык текстаЗдесь сразу три флага: m позволяет искать по каждой строке отдельно, i убирает разницу между заглавными и строчными буквами, а g собирает все подходящие строки, а не только первую. Строка про «PyThOn» не попала в результат, потому что она не начинается со слова perl ни в каком регистре.
Частые ошибки
Самая частая путаница — забыть разницу между m и g, когда речь о многострочном тексте. Флаг m меняет смысл ^ и $, а флаг g заставляет искать все совпадения, а не только первое — это два независимых поведения, и для поиска «во всех строках» обычно нужны оба сразу.
Вторая ошибка — использовать точку . в многострочном тексте и удивляться, что она не захватывает перенос строки. По умолчанию точка означает «любой символ, кроме переноса строки» — это отдельное поведение, которое флаги g, i, m не меняют (для этого есть отдельный флаг s, который выходит за рамки этого раздела).
Третья ошибка — забывать флаг i при работе с текстом, который вводят реальные люди. Пользователи печатают как попало: «Да», «ДА», «да» — если сравнивать без i, часть ответов будет незаслуженно отбракована.
Итоги
Флаги — это короткие модификаторы поведения регулярного выражения, которые пишутся сразу после закрывающего слэша шаблона. Флаг g ищет или заменяет все совпадения вместо одного, флаг i убирает чувствительность к регистру букв, а флаг m заставляет ^ и $ работать на границах каждой строки внутри многострочного текста. Комбинируя их, можно очень точно настроить поведение поиска под конкретную задачу — и в этом, пожалуй, вся суть регулярных выражений в Perl: гибкость в паре символов.