Как стать автором
Обновить

Регулярные выражения простыми словами. Часть 2

Уровень сложностиПростой
Время на прочтение10 мин
Количество просмотров23K
Всего голосов 119: ↑116 и ↓3+143
Комментарии58

Комментарии 58

Как известно, на данный момент человечество алгоритмически реализовало только два смертных греха из семи: жадность и лень, остальные пять пока ожидают своего часа.

Хах, шикарно))

Один коллега мне на это ответил: "Чур, я реализую прелюбодеяние"

Оно опоздал, множественное наследование в С++ давно реализовано.

Если у вас была проблема и вы решили ее регуляркой, то теперь у вас 2 проблемы

+71<030003764014769+92165171<

Вместо одного или всех "+" может быть "-". По краям разделителей(+-<) могут быть(а могут не быть) пробелы. Надо найти строку целиком, а потом из неё выдернуть нужный кусок(в данном случае это "030003764014769").

Если выдернуть кусок можно накостылив поиски и реплейсы в строке(хотя с регуляркой это значительно проще), то первую часть я не вижу как реализовать без регулярки(область поиска - набор строк после OCR документа).

А ещё именно наличие регулярок(помимо прочего) делает сортировщик почты в TheBat! таким мощным инструментом(я бы сказал непревзойдённым, но сравнивать могу только с разными версиями Аутлук и с Тандербирд).

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

+71<030003764014769+92165171<

Вместо одного или всех "+" может быть "-". По краям разделителей(+-<) могут быть(а могут не быть) пробелы. Надо найти строку целиком, а потом из неё выдернуть нужный кусок(в данном случае это "030003764014769").

Не совсем понял задачу. Почему нужный кусок именно 030003764014769, а не 92165171 или 71 ?

Не могу точно сказать каков смысл у строки "+71<030003764014769+92165171< " целиком, но кусок который оттуда нужно достать - Payment Reference. И его нужно передать в информационную систему после распознания документа. Остальная часть строки не требуется, но т.к. формат(с учётом некоторого креатива от составителей счёта, в виде лишних пробелов и т.п.) строки стандартный, то его удобно искать по регулярке без указания области на листе для поиска, по крайней мере ложных срабатываний не встречалось ни разу.

\s*[-+]\s*\d+\s*[<]\s*(\d+)\s*[-+]\s*\d+\s*[<]\s*

типа такого?

Почти :). На данный момент все случаи покрывает такое выражение:

[+-]{1}N{1-2}[ ]{-}([^0123456789]{1-2}|"<")[ ]{-}N{10-}[ ]{-}"+"[ ]{-}N{5-}[ ]{-}"<"{-1}

P.S. Да, тут ещё и диалект свой используется, особенно в части "расширения".

* — Any character

O_o, японский бог, зачем?? У них там какие то особенные специалисты-мозголомы такой "диалект" придумывали

Трудно сказать зачем. Возможно пытались адаптировать под конкретную задачу - например, там есть "C" для заглавных букв, и "c" для всех(а ещё нечёткий поиск типа %DIGIT% для всего похожего на цифры). А может быть упрощали синтаксис для пользователей - хотя без кодинга там будет некомфортно(что-то с синтаксисом похожим на C#), но в принципе возможно.

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


P.S. Сейчас обратил внимание что в первом наборе символов регулярки парсер хабра съел экранирование минуса, надо было вставлять как код однако...

Что такое регулярные выражения? Это измерительная рулетка, где вместо металлической ленты - резиновая. Растягивая такую рулетку можно "измерить" почти любой текст, подгоняя разметку под текст.

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

Нет. В реальной жизни того, что рассмотрено тут более, чем достаточно. Ну ещё круглые скобки и их исключения (?:

Более того, в приличных местах за всё отличное от .?*^$[]|\s\S\d\D морды бьют. Мне на собесе как-то пытались дать задачу на именованные бэкреференсы, я им сказал, что мне (и компу) проще двумя простыми регекспами без извратов. А если такую хрень в коде встречу, то перепишу, чтобы второй раз не разбираться. Мне сказали, что принят)

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

Так регекспы в принципе write only. Разбираться с ними - это все равно что старую изоленту аккуратно разматывать и переиспользовать. Проще намотать новую со свежего рулона.

Сложность разбора чужого регэкспа очень ситуативна.

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

/^[A-Za-z0-9!#$%&'*+=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+=?^_`{|}~-]+)*@(?:[A-Za-z0-9-]{1,63})+\.[A-Za-z]{2,63}$/

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

К сожалению руки чесались проверить, исправил регулярку в инструментах разработчика, и добавил свой емейл в профиле. В результате саппорт читавший запрос по диагонали, и проигнорировавший дважды скриншот с проблемой, тупо сказал - "у вас в профиле указан ваш емейл, проблемы нет". Так что проблема так и не решена, хотя я им и регулярку их прислал, и написал что поправить чтобы работало. Сбер, к слову такую проблему признал, и пофиксил.

Зато теперь у вас есть прекрасный ответ на распространённый вопрос: "Ты ж программист. А можешь банк взломать?"

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

Информативно, про жадность и лень хорошо объяснено

Например, выражение $однажды соответствует слову «однажды» только в начале строки

Опечатку нашёл. Не "$однажды", а "^однажды".

Да, такой вот я душный и нудный, если что читаю, то вычитываю побуквенно.

И не лень было тут коммент писать (выделять, делать цитату и т.д.)? Ведь можно выделить, нажать Ctrl+Enter и написать кратко - сообщение уйдёт в личку автору (куда в общем-то и надо про опечатки писать). Единственный кейс (как мне кажется), когда сюда писать про опечатки - когда нет клавиатуры (с телефона например), и искать как нажать Ctrl+Enter муторно или вообще нет возможности.

(да, в обществе зануд новый председатель :)

Ведь можно выделить, нажать Ctrl+Enter

А если с телефона?

Я же про это написал:

Единственный кейс (как мне кажется), когда сюда писать про опечатки - когда нет клавиатуры (с телефона например), и искать как нажать Ctrl+Enter муторно или вообще нет возможности.

Да и судя по тому, что там даже цитата вставлена, маловероятно, что тут с телефона. Ну да ладно, главное чтобы кто читает это увидел тоже.

Увидел, увидел. Но считаю что простые грамматические и/или орфографические опечатки да, надо отправлять именно автору через Ctrl-Enter, а на такие вот, которые могут запросто сбить с толку тех, кто регекспы увидел вообще впервые [в данном случае речь о регекспах], надо указывать открыто и прилюдно.

Есть еще один. Я как-то пытался отправить опечатку автору а мне: "Автор отключил возможность приема личных сообщений"

Ой!

Глаз не наметан на регулярки;)

Спасибо за бдительность, исправили!

Разработчики делятся на три типа: те, кто уже понимает регулярные выражения и порой решает сложные задачи одной строкой; те, кто все еще боится их и всячески избегает; и те, кто уже прочитал первую часть этой серии статей и полон оптимизма разобраться с этими магическими письменами.

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

Просто "узнали" или столкнулись на практике? Уж очень сильно это "знание" смахивает на суеверие и преждевременную оптимизацию.

Про Catastrophic Backtracking есть множество статей на Хабре. Но это уже продвинутый уровень, нужно не просто разбираться в синтаксисе, но ещё как оно там всё работает внутри.

и те, кто уже прочитал первую часть этой серии статей и полон оптимизма

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

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

"Регулярные выражения для Чайников"
Том 11

"...в заключение предисловия к введению в эту интереснейшую тему, предложу читателям 30% скидку на обслуживание в местной психиатрической клинике..."

P.S. Сори. Злоязычу :)

Столкнулся с тем, что часть выражений, которая валидна в regex101, не работает в гуглотаблицах.

А какой диалект выбираете в regex101?

Google Sheets использует движок RE2. Если я правильно понимаю, в regex101 он называется Golang.

$ — руна доллара, символизирует крах, тьму, конец строки.

Прям в точку своей актуальностью.

На заметку - выражение:
(^$\r\n)+

Позволяет в notepad++ найти и удалить все пустые строки

Только для CRLF (Windows) окончаний строк :)

Вы считаете, что надо разжевывать вплоть до того, что \r\n соответствуют CRLF?

А возможно кто-то не знает и что такое CRLF ;)

Намекает на существование юниксовых переносов и возможность обработать оба варианта. (^$\r?\n)+

Может быть не везде так, но обычно \r указывать на обязательно, \n сам подстраивается под кодировку.

Упс, вот здесь вы очень сильно нафантазировали. Попробуйте сформулировать какой-нибудь конкретный пример этого "обычно" и проверьте себя. Разумеется, ничего подобного вы не увидите.

Сейчас нет под рукой машины с виндой, поэтому проверить не могу. Но где-то что такое читал.

"\R matches any Unicode newline sequence", поддерживается только в диалектах PCRE и Java (среди диалектов на regex101).

А для Notepad++, вообще говоря, это было не нужно, в нём есть отдельная команда (Edit => Line Operations => Remove Empty Lines).

Для "обычного" поведения не нужно искать какую-то специальную программу, чтобы его продемонстрировать. Оно на то и обычное, что есть везде. Ну или наоборот - оно совсем даже необычное ;-)

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

И как пример .*

Извините, дальше читать не стал. Как-то меня выучили, что «что угодно сколько угодно раз» это всё-таки * а не точка. Наверное мои знания протухли.

В регулярках . - любой смвол, * - сколько угодно раз.

.* - любой символ сколько угодно раз.

Что не так? Или вы про маски в файлах?

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

Вот что значит писать комментарии ночью. Был не прав, приношу извинения.

Скорее, изначально были тухлыми. * - это "сколько угодно раз". А "что угодно сколько угодно раз" - это как раз .*. В статье всё написано правильно, а вот вы её читать перестали задолго до этого места, выхватив пару случайных фрагментов и перемешав их у себя в голове.

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

Если что, я, конечно, реально преклоняюсь перед теми, кто в этом как в воде. Но это надо иметь очень продвинутый мозг...

спасибо за обе статьи! получил удовольствие от стиля)

Я уже больше 20 лет в IT, и, конечно, регулярно появляются задачи, которые имеет смысл решать с помощью регулярных выражений. Я много раз разбирался с регулярками и столько же все обратно забывал. Сейчас мне проще Chat GPT попросить написать мне регулярку, чем заново все вспоминать. Кстати, способность мозга забывать - весьма недооцененная фича, на мой взгляд. Наш природный Garbage Collector позволяет избавляться от мусора, сохранять мозги в тонусе и поддерживать необходимый уровень нейропластичности для адаптации к меняющимся условиям. И так получилось, что для меня регулярки стали таким "мусором". А еще, регулярки часто работают медленнее чем алгоритмический разбор строки. Но иногда, да, на регулярках получается красиво.

  1. Если используется реализация на Java, то фильтровать символы кириллицы можно выражением \p{InCyrillic} (там есть имена и для других письменностей).

  2. Есть не только жадные и ленивые, существует три категории: Greedy, Reluctant и Possessive, там уже тонкости.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий