Pull to refresh

Comments 26

Очередная попытка убить регулярные выражения очередным велосипедом, который и 1% от их возможностей не покрывает и ничуть не делает код проще.

Не проще ли разобраться с регулярными выражениями, чтобы они вас больше не пугали?

Все мы писали свои велосипеды, это часть обучения.

Главное не тащить их потом в прод.

Согласен, посыл статьи не в том, что "гляньте, какого я убийцу фейсбука запилил", а в том, чтобы не бояться быть опозоренным, показывая свои начинания.

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

Регэкспы в таком виде действительно тяжело читать. "/x" и "/xx" перлового движка придуманы для того, чтобы можно было описать каждую деталь в комментариях.
В движках типа Nitra используется PEG для лексического анализа, что позволяет писать с заданием имён конкретным элементам выражения, комментариями, и возможностей в сумме таки больше, чем у самых выдающихся движков вроде того же перлового.
То, что именно АС сделал движок с меньшими возможностями, показывает, что он не в курсе достижений индустрии — факт, но и само по себе намерение что-то сделать в этом — похвально.

Меня пугают регулярные выражения. Не смотря на то, что я их знаю и использую. Основная причина - регэксп - это код для state machine, подобие ассемблера. Там ничего не для человека. Это write only код, который можно глазами реверс-инженерить и только. Там нет ни имён, ни мест для синтакисческого ритма (отступы, семантические блоки).

Человек, который написал длинный и суровый регэксп - справился. А как насчёт того, что будет в этом регэкспе багу ловить?

> Там нет ни имён, ни мест для синтакисческого ритма (отступы, семантические блоки).

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

re_token="[A-Za-z0-9.!%*_\\+`'~-]+"
re_quoted_string="\"([^\r\n\"\\\\]|\\\\[^\r\n])*\""
re_display_name = "\\s*((?:%s(?:\\s+%s){0,})|%s)\\s*" % \
  (re_token, re_token, re_quoted_string)
re_gen_value = "(?:%s|%s)" % (re_token, re_quoted_string)
re_gen_param = "(?:%s(?:\\s*=\\s*%s)?)" % (re_token, re_gen_value)


ну и так далее. Для парсера они предкомпилируется, и то, что у конкретного выражения может быть в итоге 1467 символов (исходник регэкспа для name-address) — уже неважно, структурно всё понятно, тестируется по кускам и так далее.

PS: Ну да, дальше предлагают механизмы, которые всё это оформляют уже в виде функций/методов — что-то вроде классического parser combinators. Если они могут потом скомпилировать результат во что-то эффективное (один автомат, как у классических регулярок) — отлично. Просто на одну зависимость больше :)

Мне кажется, написать свои регулярки — хороший способ разобраться с "классическими".

UFO just landed and posted this here

Спасибо и вам, и автору поста, который этот вопрос поднял. Выглядит (Rust-версия) как ровно то, что я хотел бы. Адекватную семантическую разметку вместо байт-кода для робота.

UFO just landed and posted this here

"Хм, regex такой сложный. НУ ПОЧЕМУ?

Ну почему он всем кажется сложный?
Регексп ПРОСТОЙ! Нужно просто сесть, прочитать одну книжку по регекспам (1-2 вечера) и посидеть немного на стековерфлоу или unixexchange посматривая задачи по регекспам и парся их. ВСЕ. Все регекспы становятся достаточно простыми.
Можно не стать супергуру, но как минимум 90% регекспов вы сможете читать сходу, и 60% из них писать сами. Как минимум если говорить по PCRE.

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

По поводу статьи: автор просто учится, думаю пет-проект просто поможет разобраться, но а ещё полезно все таки реальные примеры из жизни.

Книжку и 1-2 вечера даже много, если не пытаться конечно освоить все и сразу (а так делать вообще вредно). Ведь в принципе, базовые вещи совсем простые, и их достаточно мало.

Ведь по сути, то что автору кажется сложным, надо просто порезать на куски, и все станет понятным:

^(?!-)[A-Za-z0-9-]+([\\-\\.]{1}[a-z0-9]+)*\\.[A-Za-z]{2,6}$

^...$ — начало и конец строки, значит мы ищем совпадение не внутри строки, а со строкой целиком. Теперь про это забываем, и рассматриваем то что осталось по частям.

[A-Za-z0-9-] — латинские большие и маленькие буквы и цифры, и минус
[a-z0-9] — тоже самое маленькие буквы и цифры
[A-Za-z] — большие и маленькие буквы, без цифр на этот раз
Во всех случаях — одна штука

[]+ — одно или более повторений того что в скобках
{2,6} — от 2 до 6 повторений
{1} — ровно одно повторение

([\\-\\.]{1}[a-z0-9]+)* — а это комбинация из уже изученных вещей, как и вся регулярка в целом. Тут из нового круглые скобки, чтобы + или * применялись к группе как целому

Ну и что тут сложного, если совсем немного подумать? После этого от регулярки остались рожки да ножки — можно посмотреть в справочник, и понять, что означают остальные конструкции. А по сути, мы изучили всего несколько базовых вещей: *, +, {} как повторение, [] как диапазон символов, () как группировка, ^ И $. Ну и \\ еще.

И что я забыл, из нужного все время?

И что я забыл, из нужного все время?

Я регулярно использую lookahead и look behind, а также группы, чтобы потом можно было использовать back referenсe на сматченную группу.

Я про каждый день. А это все же продвинутые фичи.

Ну и главное — пока я уложился в одну страницу. То есть правил-то совсем немного.

Так я тоже про каждый день.

при помощи lookahead и lookbehind можно грепом вырезать не просто нужные строчки, а еще и нужные столбцы или значения из другого мусора. Одной командой.

Просто речь о разных типах сложности.
Правила регекспа просты и емки.
Это и их преимущество и недостаток.
Недостаток в том, что за счет высокой плотности правила получаются write only - их крайне тяжело читать и менять впоследствии, особенно если не делаешь это регулярно.

В моем случае это приводит к том, что правила то Я знаю, но сталкиваюсь так не часто и разнообразно (то в пайтоне, то в баше, то в шарповом коде), что каждый раз приходится мучительно вспоминать, как там начать строку, какой значок для букв и цифр и т.д.
Для моего случая verbal expression могут быть крайне удобен (да и на выходе он дает те же регекспы)

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

> Он не сложный, он read only.

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

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

> Я не понимаю, кому вообще могла прийти идея в половине случаев экранировать обычные символы, а в половине — управляющие.

Исторически. Экранировка управляющих это специфика basic syntax, а не extended syntax, который сейчас в основном развивается всеми движками. А в basic с самого начала выделили небольшой набор символов для меты (.*^$ — и всё?), а дальше развивали через \.

На самом деле, если бы в базовых сделали _все_ меты через \, было бы системнее (и проще развивать). Но уже как получилось, так получилось — ломать миллионы мест уже никто не будет.

> Но даже если и пришла, для этого нужен был ещё один человек, который сказал «Мне норм. В продакшен».

Если посмотрите историю Unix, там таких промежуточных «мне норм, в продакшен», а через месяц «ой не то, надо править» было несколько штук в неделю, какие-то мелочи могли шлифоваться с десятками переделок. В то время была поговорка «типичный пользователь Unix не знает, как на этой неделе вызывается вывод на принтер».
Через несколько лет это всё обтесалось до приемлемого состояния.

У Alex Aiken есть курс Compilers. В самом начале курса так фундаментально разбираются возможности конечных автоматов и соответствующих им регулярных выражений, что после изучения их уже нельзя забыть/не понимать/сторониться. Очень рекомендую.

Погодите, но регулярные выражения были созданы чтоб простыню кода по парсингу скомкать в компактную строку. Её нет никакого смысла раскрывать обратно, вместо этого вы могли бы взять аналогичную простыню кода и попробовать её упростить до, например, упомянутого выше, https://github.com/sprache/Sprache.

Sign up to leave a comment.

Articles