Честно: большинство тех кто пишет регулярки - просто аккуратно копируют со Stack Overflow, я сам был такой
Ноябрь 2012 года, если не ошибаюсь. Может октябрь - уже не помню точно. Мне передали чужую программу т.к. человек который её писал уволился. Быстро уволился, без передачи дел. Программа собирала заявки от клиентов: имя, телефон, адрес доставки. Мне нужно было разобраться как она не пускает людей, которые вводят в поле "имя" какую-нибудь ерунду. Ну знаете - когда человек жмёт клавиши наугад или вводит пробелы. Нашёл нужное место в коде. И там было вот это:
^(?:[а-яА-ЯёЁ]{2,}[\s\-]){1,3}[а-яА-ЯёЁ]{2,}$
Я смотрел на это. Просто смотрел. Потом скопировал в гугл, что-то почитал - не особо помогло - закрыл вкладку. Написал тому кто это написал, хотя мы едва были знакомы: "слушай, а что вот это вообще?" Ответил через два дня: "а, это проверка ФИО, там всё понятно". Я написал "ясно, спасибо". Больше не спрашивал. Строчка работала и ладно. Но это меня беспокоило. Реально беспокоило, не для красного словца. Не люблю когда в коде есть что-то чужое и непонятное - особенно в том месте где пользователи вводят свои данные. Казалось что в любой момент что-то может пойти не так а я даже не пойму где смотреть.
Что это вообще такое?
Называется эта строчка регулярное выражение. Или регулярка. Некоторые говорят паттерн. Если совсем на пальцах - это способ описать форму текста а не конкретный текст. Не "найди слово Вася" а "найди любое слово из пяти букв которое начинается на В". Или "найди строку где сначала идут одиннадцать цифр подряд" - т.е. номер телефона, неважно как именно он записан. Вот с телефонами как раз хороший пример. Допустим вам прислали базу клиентов - пять тысяч строк. И в каждой строке телефон, но записан по-разному т.к. менеджеры вносили кто как хотел:
8-916-123-45-67 +7(916)1234567 89161234567 8 916 123 45 67
Это всё один и тот же номер. Вы это понимаете сразу. Компьютер - нет. Для него это четыре разные строки которые вообще не похожи друг на друга. Без регулярок тут либо руками, либо пишешь условие для каждого варианта. Потом находишь пятый вариант которого не учёл. Потом шестой. С регулярками - один шаблон, и всё.
Я с ними помирился года через три после той истории. Не потому что сел специально учить - просто задачи заставили. Разбирать логи сервера руками надоедает быстро. Чистить таблицы с кривыми данными вручную - тем более. Когда наконец разобрался - немного обидно стало. Там не так много всего. Символов которые реально нужны - штук пятнадцать, наверное. Большинство задач решаются вообще пятью-шестью. Точка означает "любой один символ". Звёздочка - "предыдущее встречается сколько угодно раз". Значок ^ в начале - "строка начинается здесь". $ в конце - "строка здесь заканчивается". \d - "любая цифра". Это не шифровка - это просто другой алфавит с другими значениями. Привыкаешь быстро.
Есть один момент который меня в своё время поставил в тупик. Регулярки бывают жадными. Это официальный термин, не придуманный. Когда говоришь "найди всё что между словом А и словом Б" - по умолчанию берётся максимум. Если слово Б встречается в тексте три раза - дотянется до последнего. Не до первого. Вот представьте строку с жалобами жильцов - всё в одну строку, так бывает в выгрузках:
жалоба: шум в подъезде жалоба: вода холодная жалоба: Олег с третьего
Хочешь найти что написано в первой жалобе. Ожидаешь получить "шум в подъезде". Получаешь всё от начала до последней "жалоба:", т.е. почти всю строку. Потому что жадно. Лечится одним символом - вопросительным знаком в нужном месте. Было "бери максимум" - стало "бери минимум, стоп при первом совпадении". Называется ленивый режим. Жадный и ленивый - два режима, один символ разницы. Я это понял не из учебника. Я это понял когда регулярка вернула мне половину лог-файла вместо одной строки которую я искал. Минут двадцать смотрел что не так.
В Питоне регулярки работают через модуль который называется re. Подключаешь одной строчкой и дальше либо ищешь все совпадения в тексте, либо заменяешь найденное на что-то другое, либо просто проверяешь есть такое в строке или нет. Выглядит это примерно так. Вот реальная ситуация которая случается часто: выгрузка из какой-то системы, строки с ошибками вперемешку с нормальными строками. Нужны только ошибки.
2024-01-15 ОШИБКА Иванова: дубликат записи
2024-01-16 ОК Петров: данные обновлены
2024-01-17 ОШИБКА Сидорова: неверный формат даты
2024-01-18 ОК Кузнецов: обновлено
2024-01-19 ОШИБКА Олег: снова что-то пошло не так
Для обработки пишу такой код
import re
errors = re.findall(r"^\d{4}-\d{2}-\d{2} ОШИБКА.*$", data, re.MULTILINE)
Читается примерно так: найди строки которые начинаются с даты - четыре цифры, дефис, две цифры, дефис, две цифры - потом идёт слово ОШИБКА, потом что угодно до конца строки. Всё остальное пропусти. Результат: три строки с ОШИБКА. Строки с ОК не попали. Одна строка вместо цикла с кучей условий.
Если вы никогда не видели Питон и непонятно что там написано - import re это просто "подключи инструмент для регулярок", без этого ничего не работает. re.findall - найди всё что подходит и верни списком. Остальное пока не важно.
Вернёмся к загадочной строчке из начала поста:
^(?:[а-яА-ЯёЁ]{2,}[\s\-]){1,3}[а-яА-ЯёЁ]{2,}$
Сейчас я читаю эту строчку примерно так: строка начинается и заканчивается кириллическими буквами, каждая часть минимум два символа, между частями пробел или дефис, таких частей от одной до трёх. Т.е. это проверка ФИО. Иванов Иван Иванович - пройдёт. "абракадабра" - нет. Пробелы - нет. Одна буква - нет. 3 минуты ступора тогда, 30 сек сейчас. Разница только в том что я теперь знаю что означают символы.
Я учил регулярки по кускам. Что-то из документации, что-то с Stack Overflow, что-то методом тыка - написал, не работает, поменял, заработало, не очень понял почему. Так и накапливалось. Это нормальный способ, я не жалуюсь. Но медленный. И каждый раз когда кто-то из коллег спрашивал "объясни как это работает" - я объяснял одно и то же. И каждый раз чувствовал что объясняю как-то криво. Не потому что сам не понимаю, а потому что под рукой не было нормального места куда можно было бы отправить человека. Есть доки - но они для тех кто уже знает. Есть статьи, но они на два часа, после которых всё равно идёшь в гугл.
Со временем я сделал курс. Провозился дольше, чем планировал, но зато сделал его так, как сам хотел бы проходить. Плюс справочники, я сам ими пользуюсь т.к. всё наизусть не помню. Не знаю подойдёт ли именно вам. Если просто хотели понять что такое регулярки и почему они выглядят как шифровка - надеюсь этот пост помог. Написал 72 урока и более 900 задач. 900, Карл! Теперь вижу регулярки во сне - это уже не лечится 🙃 Первые 7 уроков открыты, добро пожаловать в секту: Регулярные выражения (Regex) в Python: Интерактивный тренажер
И последнее. Вот строка из реальной почты, такое приходит, когда коллега пересылает что-то важное простым текстом:
Встреча с Ивановым перенесена. Новое время: 14:30.
Попробуйте написать шаблон, который вытащит из этой строки только время - «14:30». Две цифры, двоеточие, две цифры. Казалось бы, вроде бы просто, но интересно, как вы это запишете на языке регулярок. Пишите варианты в комментариях, позже разберём. Рабочих решений несколько, посмотрим, кто до каких доберётся 🙂







