//

Мысли (Автор: dez)

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

Регулярные выражения (regex или regexp) - это своеобразный язык, позволяющий описывать шаблоны для поиска подстрок в тексте. Такие подстроки могут отличаться друг от друга, но при этом они будут иметь общий формат или подчиняться каким-то одним и тем же правилам. Например, если нужно найти в тексте все номера телефонов или слова длиннее N букв - регулярки в помощь.

 

Где-то я такое уже видел...

В более простой форме идея поисковых шаблонов знакома, наверно, почти всем, чья жизнь тесно связана с компами. При поиске файлов на диске или при массовой их обработке каким-нибудь скриптом часто используется символ * (звёздочка). Он как бы говорит компьютеру: "Тут может быть что угодно, мне пофиг." Если в шаблоне написать *.png, то будут найдены все файлы с расширением png. В этом случае звёздочка - символ-джокер, или wildcard, а шаблон такого типа называют glob pattern или wildcard pattern. Это не единственный такой символ, но, пожалуй, самый полезный и часто употребляемый.

Регулярные выражения в целом похожи на поисковые запросы с символами-джокерами, только на стероидах. Они позволяют устанавливать количество символов в искомой последовательности, искать совпадения с одной из нескольких альтернатив, позволяют завернуть шаблон в группу и сделать с ней шаблон покруче, и наверно ещё что-то, о чём могу даже не подозревать. При этом важно понимать, регулярки НЕ являются чем-то обратно совместимым с обычными шаблонами (glob). Это две разные вещи! Позже в этом посте будет один пример, где можно наколоться.

Не всё подряд поддерживает регулярки. Командная строка Linux и утилита find работают с обычными шаблонами. А вот утилита-фильтр grep (аналог в Windows - команда findstr) ожидает в качестве шаблона именно регулярное выражение. Также поиск с помощью регулярок возможен в LibreOffice и Notepad++, если включить соответствующий режим.

 

Сколько вешать в граммах?

Теперь перейдём ближе к делу. Посмотрим для примера на задание количества (квантификацию). Мы можем сформулировать шаблон так, чтобы символ или группа повторялись определённое число раз - для этого используются фигурные скобки. Запросу ab{4}cde будет соответствовать строка abbbbcde. Требуемое количество повторений может быть задано не только одним конкретным числом, но и интервалом - a{2,5} будет означать от 2 до 5 букв 'а' подряд.

Но фигурные скобки - это общий случай. Есть и другие, более лаконичные квантификаторы специально для распространённых ситуаций.

? 0 или 1 
* 0 или больше 
1 или больше 

Так, по шаблону colou?r можно найти как слово color, так и colour.

Здесь важно обратить внимание на звёдочку, потому что её смысл в регулярных выражения очень сильно отличается в сравнении с обычными поисковыми шаблонами! На ХаДе в 2021 году постили поучительную историю про то, как в каком-то большом проекте пытались с помощью grep посчитать количество вызовов функции fork() и получили число порядка миллиона. При поиске был использован шаблон fork*, которому в контексте регулярок соответствуют строки fork, forkk и... просто for, без всякого k. То есть вдобавок ещё количество циклов for посчитали, хотя в планы это не входило.

 

Тайные знаки

И раз пошла речь про звёздочку, есть смысл упомнятуть метасимвол . (точка) - он означает один любой символ. Например, звёздочке из обычного поискового шаблона будет соответстовать регулярное выражение

.*

Оно срабатывает на последовательности каких угодно символов какой угодно длины (в том числе нулевой).

Мы только-только начали погружаться в тему, но некоторая картина уже вырисовывается. Регулярные выражения - это нечто, обладающее своим хитрым синтаксисом. И этот синтаксис требует жертв в виде печатных символов. К этому моменту у читателя мог назреть вопрос - а что делать, если все эти звёздочки, точки, скобочки и плюсики интересуют нас как часть искомой строки, а не как служебные символы? Ответ - экранирование. Делается это при помощи \ (бэкслэша) перед экранируемым символом. Ищем фигурную скобку - пишем \{, ищем бэкслэш - пишем \\, и так далее. После программирования на C или работы c командной строкой это выглядит вполне привычно.

Ещё один интересный спецсимвол, про который хотелось упомянуть - ^ (карет, "домик" или циркумфлекс). Он является якорем, означающим начало строки. Это не единственный якорь, но, наверно, наиболее часто употребляемый. Применяется, когда надо по каким-то критериям найти целую строку и обработать её только один раз, то есть шаблон не должен многократно срабатывать в пределах одной строки.

 

Не все буквы одинаково полезны

На одних квантификаторах далеко не уедешь. Поэтому ещё одна базовая вещь, которую стоит упомянуть - символьные классы. Их задают с помощью квадратных скобок и применяют тогда, когда искомый символ должен входить в некий список допустимых символов. Шаблон [abcde] означает одну букву из указанных пяти, а [0-9] ищет символы, являющиеся арабскими цифрами.

Символьные классы делают возможным составление шаблонов для поиска разных подстрок с общим форматом, таких как дата и время, IP-адреса, номера телефонов, регистрационные знаки транспортных средств и прочее.

 

Групповуха

С квантификаторами и символьными классами уже можно составлять довольно полезные запросы, но у регулярок в арсенале ещё предостаточно всяких инструментов. Например, группы.

Группа создаётся путём заключения шаблона или его части в круглые скобки. Какая с этого польза? Тут несколько ответов. Первая мысль лежит на поверхности - с группой можно делать то, что мы до этого делали лишь с отдельными символами. Если задать шаблон (ля){4}, ему будет соответствовать строка ляляляля. Кроме того, группу можно рассматривать как своего рода переменную, которую можно повторно использовать. Если в выражении есть группа или несколько групп, то им будут присвоены номера (при желании этого можно избежать), начиная с 1. Подстрока, совпавшая с шаблоном внутри группы, будет запомнена - получить её можно через бэкслэш и ID группы, например \1. Эту подстановку удобно применять в строке замены, когда результат поиска нужно обработать без потери информации - просто выделить скобками или ещё чего-нибудь эдакое.

Так же группы могут помочь сделать запрос более читаемым, коротким и элегантным. Когда нам нужно повторно использовать именно шаблон группы, а не результат совпадения с ним, нужно в скобках поставить вопросительный знак и номер группы, например (?1).

Здесь можно рассмотреть пример с автомобильными номерами РФ. Их формат: 1 буква, 3 цифры, 2 буквы, код региона из 2 или 3 цифр. Причём набор букв ограничен символами, имеющими "аналоги" в латинском алфавите (12 букв). Шаблон для поиска валидных номеров можно сформулировать так:

([АВЕКМНОРСТУХ]){1}[0-9]{3}(?1){2}[0-9]{2,3}

Для краткости в нём не учитываются буквы нижнего регистра, а так же латиница. Подстановка (?1) позволяет не пихать туда лишний раз АВЕКМНОРСТУХ и тем самым сделать запрос короче раза в два. Если бы вместо этого стояло \1, шаблон работал бы не так, как изначально задумано - нашлись бы только номера с 3-мя одинаковыми буквами. Другое дело, если искать надо только блатные номера - тогда да, тут бы и \1 и даже \2 пригодились.

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

 

Закругляемся

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

Для дальнейшего погружения можно почитать википедию, а ещё очень советую воспользоваться сайтом regex101. Это одновременно и шпаргалка, и тренировочный полигон.

Статья опубликована 2025-03-03 14:20:50, её прочитали 207 раз(а).

Внимание! Комментарии публикуются после проверки (что занимает некоторое время).
Сообщение может быть отклонено, если содержит спам, противозаконный контент, а так же оскорбления и грубость по отношению к другим участникам обсуждения.

Добавить комментарий