Классический сухой регекс:

/^(?:[0-9]|[a-z]|[\._%\+-])+(?:@)(?:[0-9]|[a-z]|[\.-])+(?:\.)[a-z]{2,}$/i

С новым вкусом SLR:



На пост заметка не тянет, но на новость вполне. Дабы не тянуть кота за хвост, я вынес суть выше хабраката. Теперь потяну. В духе Хабра-Твиттера, прошу любить и жаловать: simple-regex.com — создание регулярок простым языком.

Для начала, это не я придумал, к сожалению. Сайт на английском, статьи как таковой нет, поэтому я не могу представить вам перевод. Сегодня я заглянул в привычный PHP подреддит, и увидел там тему «I've built a SQL-like language that compiles to regular expressions — What do you think?», по-русски «Я создал SQL-подобный язык, который компилируется в регулярные выражения». Вот так, ни больше ни меньше. Как написано в одном комментарии «Поздравляю! Ты только что сделал одно из моих самых мистических умений устаревшим!» Поэтому спешу поделиться с Хабра-сообществом, дабы все были в курсе.

Да, это близкий к естественному языку способ создания регулярок. На сайте можно найти несколько примеров. Тот, что я привёл вверху — проверяет почтовые адреса.

А вот этот:

begin with capture (letter once or more) as "protocol",
literally "://",
capture (
    letter once or more,
    any of (letter, literally ".") once or more,
    letter at least 2 times
) as "domain",
(literally ":", capture (digit once or more) as "port") optional,
capture (literally "/", anything never or more) as "path" until (any of (literally "?", must end)),
literally "?" optional,
capture (anything never or more) as "parameters" optional,
must end,
case insensitive

Служит для проверки URL, и компилируется в такую регулярочку, что Хабр даже не позволяет её правильно отобразить, поэтому я не могу её вставить, простите. Но в разделе примеров ещё много примеров. И на сайте они цветные, там читать удобнее, так что посетите, не пожалеете.



Чего на сайте я не нашёл, но что очень просится, так это реализация цепочки вызовов для задания условий. Но это есть в репозитории!

$query = SRL::startsWith()
    ->anyOf(function (Builder $query) {
        $query->digit()
            ->letter()
            ->oneOf('._%+-');
    })->onceOrMore()
    ->literally('@')
    ->anyOf(function (Builder $query) {
        $query->digit()
            ->letter()
            ->oneOf('.-');
    })->onceOrMore()
    ->literally('.')
    ->letter()->atLeast(2)
    ->mustEnd()->caseInsensitive();

Насколько это полезно покажет время. Но для начинающих программировать это явно очень упрощает тему знакомства с регулярками.

Я честно говоря, не знаю, кто автор этой штуки, но она выглядит весьма интересно. Тема на реддите размещена юзером AndroTux. Вот ссылка на репозиторий на ГитХабе. Тут можно видеть, что единственный контрибутор проекта — Karim Geiger, который разместил этот проект в репозитории компании tyvr.net, которая указана у него же в профиле. Видимо, это его же студия программистов, которые программируют за деньги. Желаю им удачи!
Поделиться с друзьями
-->

Комментарии (71)


  1. vlreshet
    31.08.2016 09:14
    +8

    Просто заменить символы на слова? А зачем? Тот кому понадобится работать с регулярками — и так знает синтаксис. Тот кто не знает — ему и не нужно, скорее всего. Да и куда такую простыню в коде девать? А подсветка как?

    P.S. да и вообще, менять знаки на слова — у меня сразу возникают ассоциации с Turbo Pascal, и его begin, end…


    1. igordata
      31.08.2016 09:19
      +3

      Зачем — не знаю. Если работать через класс SLR, как в примере на ГитХабе, то будет и подсветка, и автокомплит в IDE.


    1. x512
      31.08.2016 09:22
      +7

      А то, что приятные глазу команды процессора в машинном коде заменены на всякие операторы и идентификаторы у вас неприятных ассоциаций не вызывает?)


      1. vlreshet
        31.08.2016 14:20
        +2

        Не то сравниваете. В ЯП высокого уровня, один знак/символ/слово заменяет целый набор машинных кодов. Мы просто присвоили переменной значение (пара символов кода) — а «под капотом» произошла уйма всего. А тут — прямая замена 1:1, никакого выигрыша по удобству.


    1. fireSparrow
      31.08.2016 09:50
      +1

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


      1. Slipeer
        31.08.2016 12:38
        +10

        ИМХО классическая регулярка читабельней и нагляднее.


        1. Rastishka
          31.08.2016 13:55

          Привычнее — да.
          Читабельнее и нагляднее — вряд ли.


      1. Halt
        31.08.2016 13:26
        +2

        Во-первых, регулярные выражения можно разрывать комментариями. Во вторых, можно заводить метапеременные, которые использовать в выражениях.


        1. stychos
          31.08.2016 14:56

          Кстати да, для меня метапеременные совсем недавно оказались настоящим откровением.


        1. thewizardplusplus
          31.08.2016 21:56

          Подскажите, пожалуйста, что это за метапеременные такие? Пытался гуглить "regex metavars", но безрезультатно.


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


          Или вы имеете ввиду определение переменных с кусками регулярок в самом языке, из которого они вызываются, а потом конструирование из них финального выражения через подстановку?


          1. grossws
            01.09.2016 09:38
            +2

            man 3 pcrepattern, раздел subpatterns as subroutines.


            Регулярка типа (sens|respons)e and \1ibility даст совпадение в случае sense and sensibility и response and responsibility, но не sense and responsibility. Если же использовать (sens|respons)e and (?1)ibility, то заматчится и sense and responsibility.


    1. fedorro
      31.08.2016 11:21
      -1

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


    1. smaugfm
      31.08.2016 14:01
      +1

      Именно. Заменить символы на слова. Потому что люди воспринимают слова лучше чем символы. А мы ведь пишем код для людей а не для компьютера?


      1. vintage
        31.08.2016 14:33
        +4

        На самом деле люди мыслят образами. И правильно подобранные символы, позволяют быстрее считывать образ, чем чтение слов. Например, скобочки окружают некоторую область куда нагляднее, чем begin..end.


    1. Pinsky
      31.08.2016 14:20

      скорее кобол уже


    1. s-kozlov
      01.09.2016 07:43

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


      1. Gummilion
        05.09.2016 14:38
        +1

        А я запомнил так, что на клавиатуре $ идет перед ^, а в регулярках наоборот: $ — конец, ^ — начало.


        1. s-kozlov
          06.09.2016 05:56

          Даже это контринтуитивно


      1. punkkk
        06.09.2016 13:40

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


        1. grossws
          06.09.2016 14:21

          У меня caret (который вы назвали circumflex) ассоциируется с CR (\r).


          1. punkkk
            06.09.2016 15:00

            Хех, мне когда то говорили, что это циркумфлекс… Жизнь не станет прежней.


            1. grossws
              06.09.2016 16:59

              Я был уверен, что circumflex — диакритический знак [1], [2], а не standalone. В современном unicode u+5e называется circumflex accent (ранее я его видел под именем ascii caret) [3], а caret — это u+2038 [4].


              Извините за непреднамеренное разрушение мира ,)


              1. punkkk
                06.09.2016 17:05

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

                Да ничего, всегда полезно узнать, где ошибался. :)


  1. franzose
    31.08.2016 09:23
    -5

    Сначала подумал, было, написать про «Владимирский астрал, эзотерика», но потом решил, что не буду.


  1. wolfandman
    31.08.2016 09:29
    +10

    А почему нет? Мне нравится идея. Не думаю, что сам бы использовал, т.к. к регуляркам привык, но для новичков — вполне бы сгодилось.


    1. EvilsInterrupt
      31.08.2016 11:52
      +1

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


  1. AndreyNagih
    31.08.2016 09:36
    +4

    Картинку xkcd про единый стандарт уже постили?


  1. Bomon
    31.08.2016 09:50

    Как средство обучения rx было бы, как мне кажется, вполне удобоваримо. Хотя для тех кто синтаксис уже освоил, вероятно будет неудобно.


    1. s-kozlov
      01.09.2016 07:44
      -1

      Многословно — да. Неудобно — ну это как посмотреть. Регулярки — одна из самых отвратительных вещей в программировании.


  1. bromzh
    31.08.2016 10:17
    +3

    Сайт не отвечает, видимо его постиг хабраэффект.


    Для разъяснения и тестирования регекспов есть, например, отличный ресурс: https://regex101.com/
    А вводить новый непонятный синтаксис регекспов — не слишком хорошая идея.


  1. Sirion
    31.08.2016 10:32
    +8

    Главная проблема регекспов в том, что они write-only. Описанный в статье подход эту проблему решает. Хотя любители однострочников на перле негодуют, да.

    Не знаю, буду ли использовать, но запомню, что существует.


    1. impwx
      31.08.2016 10:37
      +9

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


      1. Fedcomp
        31.08.2016 11:00
        -4

        Проблема чтения машинных кодов решается в выравнивании кода и расставлении комментариев. Но мы же не используем машинные коды правда?


        1. impwx
          31.08.2016 11:24
          +12

          Синтаксис регулярных выражений — это уже мнемоническая надстройка над внутренним представлением, как ассемблер над машинными кодами. Предлагаемый в статье вариант не создает новый уровень абстракции, а просто заменяет одну строку на другую, более длинную — как если бы вместо mov ax, 0 пришлось писать set first register to value zero.


          1. asoukhoruchko
            31.08.2016 13:38
            -2

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


            1. impwx
              31.08.2016 14:08
              +5

              Сложность понимания синтаксиса регулярок, имхо, преувеличена. На первый взгляд они выглядят пугающе, но по факту возможные элементы можно пересчитать по пальцам — группы, квантификаторы, альтернативы, штук пять спецсимволов и всякие редкие вещи типа опережающих проверок. Всё это можно запомнить за вечер, а с подсветкой синтаксиса становится еще проще. Так что всё упирается в сложность самого выражение — проверку email-адреса по RFC одинаково невозможно постичь в любой форме записи.

              Остается вопрос того, стоит ли доверять человеку без подготовки править код, руководствуясь наивным пониманием синтаксиса. Зачастую это чревато возникновением сложноуловимых багов — например, неопытный программист на C или JS может написать if(a = true) и долго удивляться, почему сравнение не работает, как надо.


  1. nitso
    31.08.2016 10:58
    +6

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

    ^[0-9a-z._%+-]+@[0-9a-z.-]+\.[a-z]{2,}$

    И, наконец, Прекратите проверять Email с помощью регулярных выражений!

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

    Сложные выражения в SLR займут экран, воспринимать будет даже сложнее, чем открытый в отладчике (упомянутый выше regex101, например) оригинал.

    А есть специальные сервисы для визуализации regex
    1. igordata
      31.08.2016 11:16
      -5

      Проверка имейла регуляркой по большому счёту может быть сведена до /.+@.+/, но это же просто пример. Можете написать автору и предложить свой пример, заодно потестируете новую тулзу.


      1. punkkk
        02.09.2016 13:19
        +2

        Вы немного не уловили… Сократить регулярку != урезать. nitso сократил, а вы урезали. Хотя проверять email регулярными выражениями достаточно непрактично.


        1. igordata
          03.09.2016 11:29
          +3

          Учитывая существование национальных доменов, я не могу сказать что проверка мыла на латинский алфавит имеет хоть малейший смысл…


  1. vintage
    31.08.2016 11:31
    +9

    Лучше всё же, использовать грамматики, а не "очеловечивать" регулярки. Например, для вашего парсера урлов можно запилить такую грамматику на grammar.tree:


    URL is
        PROTOCOL
        string =://
        DOMAIN
        optional
            string =:
            PORT
        PATH
        optional QUERY
    
    PROTOCOL is list-of LETTER
    
    DOMAIN is
        list-of
            list-of LETTER
            string =.
        LETTER
        list-of LETTER
    
    PORT list-of DIGIT
    
    PATH is
        string =/
        optional list-of symbol except =?
    
    QUERY is
        string =?
        optional list-of symbol except =#
    
    LETTER is symbol =abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
    DIGIT is symbol =0123456789
    


    1. k12th
      31.08.2016 12:57
      +1

      А можно ссылочку? А то гугл выдает только хип-хоп дуэт.


      1. Evengard
        31.08.2016 13:27
        +1

        https://habrahabr.ru/post/248147/ кажется это оно. Там есть раздел про этот grammar.tree

        Собственно ощущение что это и есть придумка господина vintage.


        1. vintage
          31.08.2016 14:35

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


    1. s-kozlov
      01.09.2016 07:48

      О боже, в Вашем «убийце YAML» всё еще используется " =".


      1. vintage
        01.09.2016 10:12

        А какой символ порекомендуете для маркера начала сырых данных?


        1. s-kozlov
          01.09.2016 11:44

          Вам уже в комментах к той статье говорили, что "=" и " = " читабельнее " =".


          1. vintage
            01.09.2016 12:13

            И я не раз повторял, что "=" — не разделитель "ключа" и "значения". Я согласен, что символ равенства вводит в заблуждение и было бы правильнее использовать какой-либо другой символ, например "|", но он в разных раскладках набирается разными способами, что несколько фрустирует.


            1. vintage
              01.09.2016 12:20

              Хотя, я тут подумал, из символов, набираемых одинаково в любой раскладке ("-", "_", "=", "+", "\") лучше подойдёт символ обратной косой черты. Он достаточно редкий в обычных данныхи используется в основном для похожей задачи — экранирования символов.


  1. Miraage
    31.08.2016 12:01
    +2

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


    1. VladC
      31.08.2016 12:20
      +2

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


      1. saluev
        31.08.2016 20:04

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


  1. asoukhoruchko
    31.08.2016 13:50

    По факту получили Builder для регулярок, что неплохо (и даже можно подумать про портировать на другие языки).
    Отдельный язык для такой задачи кмк перебор. Т.е. пока не ясно, как это использовать для самостоятельных задач.


  1. ifgem
    31.08.2016 14:01
    +2

    У Rebol/Red есть невероятно удобный и читабельный PEG диалект(parse).
    Первый пример из статьи.


    test: "superb@ya.ru"
    digit: charset [#"0" - #"9"] ; еще один диалект.
    letter: charset [#"a" - #"z" #"A" - #"Z"]
    symbol: charset "._%+-"
    
    rule: [
        some [digit | letter | symbol]
        "@"
        2 [letter | "."] any [letter | "."]
    ]
    
    parse test rule


  1. pengyou
    31.08.2016 14:30
    -2

    Уважения заслуживают такие люди, как автор этого языка, которые делают Своё.


    1. akastargazer
      31.08.2016 15:14
      +2

      Зачем делать Своё, когда есть серьёзные и, главное, надёжные корпорации, которые сделают Своё лучше и быстрее? Если уже не сделали. Они же нам выдадут это бесплатно, в рамках рыночного планетарного прогрессорства.


      1. Pinsky
        31.08.2016 16:12

        Just For Fun


      1. vintage
        31.08.2016 16:46

        Затем, чтобы эти серьёзные и (главное!) надежные корпорации, взяли тебя на работу и ты делал Своё лучше и быстрее. :-D


  1. stychos
    31.08.2016 14:59
    +1

    Отрадно увидеть что-то действительно новое, пусть сообщество и плюётся кое-где.


  1. punkkk
    31.08.2016 15:29
    +4

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

    Одно begin with, вместо циркумфлекса уже настораживает.


    1. saluev
      31.08.2016 20:07
      +1

      Меня вот больше напрягает literally "@" вместо просто "@". Но зато действительно сложные регулярки, со всякими несъедающими группами, отрицаниями и переменными, может стать легче читать (а главное — редактировать).


      1. nitso
        01.09.2016 11:43

        Чуть выше уже оставлял ссылку: https://www.debuggex.com/r/xfu903DPxHkmoOpz
        Очень помогает отлаживать сложные выражения.


        1. nitso
          01.09.2016 11:56

          Ошибся веткой


          1. dmitryredkin
            01.09.2016 12:02
            +1

            Да, но он не транслирует обратно. С ним конечно легче найти ошибку, но если бы можно было редапктриовать саму схему — вот тогда был бы сервис.


          1. dmitryredkin
            01.09.2016 15:56

            Кроме того, заметил, что он показывает не все. Например, вопросик aka «non-gready capture» пропускается совсем.


  1. dmitryredkin
    31.08.2016 16:01
    +1

    Как уже было замечено выше, на самом деле нужен не компилятор regExp, а декомпилятор регулярок (как в сервисах визуализации в комментарии выше). И вот если бы оно умело работать в обе стороны — вот это было бы дело!
    Ну реально: Вот вы бы отказались от такого сервиса?


    1. nitso
      01.09.2016 11:57

      Попутал ветку и ответил в предыдущем комментарии.


  1. kompi
    01.09.2016 00:21

    Если хочется красоты, то можно использовать альтернативу — https://en.wikipedia.org/wiki/Parsing_expression_grammar. Использовал PEG в lua — довольно-таки удобно.


  1. L0m
    01.09.2016 00:21
    -1

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


  1. Athari
    01.09.2016 01:07
    +2

    Классический сухой регекс:
    /^(?:[0-9]|[a-z]|[\._%\+-])+(?:@)(?:[0-9]|[a-z]|[\.-])+(?:\.)[a-z]{2,}$/i

    Это мусор, который генерирует библиотека что ли? Потому что в .NET я ручками написал бы так:


    (?inx)
      ^
      [ 0-9 a-z \._%\+- ] +
      @
      [ 0-9 a-z \.- ] +
      \.
      [ a-z ] {2,}
      $

    Ну и что более читаемо: это или ваша портянка?


  1. viatro
    01.09.2016 09:08

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