Open nin-jin opened 3 years ago
между импортом и регулярками кард, мб что-нибудь попроще вставить?
как вариант, показать что из себя представляют импортируемые штуки
static decimal_only = $mol_regexp.from( /\d/gsu )
static end = $mol_regexp.from( /$/gsu )
Нужно делать усилия что бы интерпретировать from(...)
, конечно не такие, что бы понять что в простой регулярке написанно. Рядом с примерами карт можно на регулярках тоже самое показать.
regexpVISA = /4\d{12,12}(\d\d\d)?/
// написал без шпаргалки)
const VISA = from([
'4',
repeat( decimal_only, 12 ),
[ repeat( decimal_only, 3 ) ],
])
Пример с имейлом, немного легче было бы понять с объяснениями какую часть имейла данный токен парсит
Статья, кажется, больше обзорная. Было бы интересно почитать про как оно внутри работает, с какими проблемами борется и че-нибудь типа гайда как пользоваться. Хотя как пользоваться и тут достаточно описано, все что можно импортнуть можно в исходниках увидеть
Спасибо, добавил дампы генерируемых регулярок, пояснения по имейлу и дополнительный раздел с описанием внутренних трудностей.
Да, то что регулярки не композиционируемые это давно известная проблема. Люди кто их проектировал похоже не читали про монады и ФП. В перле для этого придумали Regexp::Grammars, очень удобная вещь.
Насчет реализации из статьи, все вроде бы классно. Особенно нравится возможно сгенерить строку соответствующую регулярке.
Единственное, я так понимаю она позиционируется как часть "эко-системы МАМ", что, думаю, отразится на популярности, поскольку изучать новую эко-систему для решения одной частной задачи мало кто будет. Но это уже на усмотрение автора.
А так стоящая вещь, достойная релиза, доки https://github.com/hyoo-ru/mam_mol/tree/master/regexp конечно тоже можно улучшить
В доках я бы сделал упор на слово composable:
$mol_regexp
Build composable regular expressions, which compiles to native RegExps. Generate a sample matching string for them.
Да оно как-то не особо привязано к MAM экосистеме. Можно использовать и из NPM.
Спасибо за советы, опубликовал на Хабре.
https://page.hyoo.ru/#!=7elk22_ykxz0c
Здравствуйте, меня зовут Дмитрий Карловский и раньше я тоже использовал Perl для разработки фронтенда. Только гляньте, каким лаконичным кодом можно распарсить, например, имейл:
Тут, правда, закралось несколько ошибок. Ну ничего, пофиксим в следующем релизе!
Шутки в сторону
По мере роста, регулярки очень быстро теряют свою понятность. Не зря в интернете есть десятки сервисов для отладки регулярок. Вот лишь некоторые из них:
А с внедрением новых фичей, они теряют и лаконичность:
У регулярок довольно развесистых синтаксис, который то и дело выветривается из памяти, что требует постоянное подсматривание в шпаргалку. Чего только стоят 5 разных способов экранирования:
В JS у нас есть интерполяция строк, но как быть с регулярками?
Ну, или у нас есть несколько простых регулярок, и мы хотим собрать из них одну сложную:
Короче, писать их сложно, читать невозможно, а рефакторить вообще адски! Какие есть альтернативы?
Свои регулярки с распутным синтаксисом
Полностью своя реализация регулярок на JS. Для примера возьмём XRegExp:
В общем, всё те же проблемы, что и у нативных регулярок, но втридорога.
Генераторы парсеров
Вы скармливаете им грамматику на специальном DSL, а они выдают вам JS код функции парсинга. Для примера возьмём PEG.js:
Пример в песочнице.
Это решение более мощное, но со своими косяками. И по воробьям из этой пушки стрелять не будешь.
Билдеры нативных регулярок
Для примера возьмём TypeScript библиотеку $mol_regexp:
Это куда более легковесное решение. Давайте попробуем сделать что-то не бесполезное..
Номера банковских карт
Импортируем компоненты билдера
Это либо функции-фабрики регулярок, либо сами регулярки.
Ну или так, если вы ещё используете NPM
Пишем регулярки для разных типов карт
В фабрику можно передавать:
Компонуем в одну регулярку
Строка списка карт
Сам список карточек
Парсим текст регуляркой
Тут, правда, есть небольшое отличие от нативного поведения.
matchAll
с нативными регулярками выдаёт токен лишь для совпавших подстрок, игнорируя весь текст между ними.$mol_regexp
же для текста между совпавшими подстроками выдаёт специальный токен. Отличить его можно по отсутствию поляgroups
. Эта вольность позволяет не просто искать подстроки, а полноценно разбивать весь текст на токены, как во взрослых парсерах.Результат парсинга
Заценить в песочнице.
E-Mail
Регулярку из начала статьи можно собрать так:
Но просто распарсить имейл - эка невидаль. Давайте сгенерируем имейл!
Упс, ерунду сморозил... Поправить можно так:
Или так:
Погонять в песочнице.
Роуты
Представим, что сеошник поймал вас в тёмном переулке и заставил сделать ему "человекопонятные" урлы вида
/snjat-dvushku/s-remontom/v-vihino
. Не делайте резких движений, а медленно соберите ему регулярку:Теперь подсуньте в неё урл и получите структурированную информацию:
А когда потребуется сгенерировать новый урл, то просто задайте группам нужные значения:
Если задать
true
, то значение будет взято из самой регулярки. А еслиfalse
, то будет скипнуто вместе со всем опциональным блоком.И пока сеошник радостно потирает руки предвкушая первое место в выдаче, незаметно достаньте телефон, вызовите полицию, а сами скройтесь в песочнице.
Как это работает?
Нативные именованные группы, как мы выяснили ранее, не компонуются. Попадётся вам 2 регулярки с одинаковыми именами групп и всё, поехали за костылями. Поэтому при генерации регулярки используются анонимные группы. Но в каждую регулярку просовывается массив
groups
со списком имён:Наследуемся, переопределям
exec
и добавляем пост-процессинг результата с формированием в нём объектаgroups
вида:И всё бы хорошо, да только если скомпоновать с нативной регуляркой, содержащей анонимные группы, но не содержащей имён групп, то всё поедет:
Чтобы такого не происходило, при композиции с обычной нативной регуляркой, нужно "замерить" сколько в ней объявлено групп и дать им искусственные имена "0", "1" и тд. Сделать это не сложно - достаточно поправить регулярку, чтобы она точно совпала с пустой строкой, и посчитать число возвращённых групп:
И всё бы хорошо, да только
String..match
иString..matchAll
клали шуруп на наш чудесныйexec
. Однако, их можно научить уму разуму, переопределив для регулярки методыSymbol.match
иSymbol.matchAll
. Например:И всё бы хорошо, да только тайпскрипт всё равно не поймёт, какие в регулярке есть именованные группы:
Что ж, активируем режим обезьянки и поправим это недоразумение:
Теперь TypeScript будет брать типы для
groups
из переданной регулярки, а не использовать какие-то свои захардкоженные.Ещё из интересного там есть рекурсивное слияние типов групп, но это уже совсем другая история.
Напутствие
Но что бы вы ни выбрали - знайте, что каждый раз, когда вы пишете регулярку вручную, где-то в интернете плачет (от счастья) один верблюд.