Лучшие идеи синтаксиса регулярных выражений

Мне нужна помощь, чтобы дополнить мое представление о регулярных выражениях.

Введение

Был вопрос о лучшем синтаксисе для регулярных выражений в SE, но я не думаю, что я бы использовал свободный синтаксис. Конечно, это хорошо для новичков, но в случае сложного регулярного выражения вы заменяете строчку тарабарщины на целую страницу немного лучшей тарабарщины. Мне нравится подход Мартина Фаулера , в котором регулярное выражение состоит из более мелких частей. Его решение читаемо, но сделано вручную; он предлагает умный способ создания сложного регулярного выражения вместо класса, поддерживающего его.

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

final MyPattern pattern = MyPattern.builder()
.caseInsensitive()
.define("numberOfPoints", "\\d+")
.define("numberOfNights", "\\d+")
.define("hotelName", ".*")
.define(' ', "\\s+")
.build("score `numberOfPoints` for `numberOfNights` nights? at `hotelName`");

MyMatcher m = pattern.matcher("Score 400 FOR 2 nights at Minas Tirith Airport");
System.out.println(m.group("numberOfPoints")); // prints 400

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

  • определяют именованные шаблоны и используют их, заключая в обратные кавычки
    • `name` создает именованную группу
      • мнемоника: оболочка фиксирует результат команды, заключенный в обратные кавычки
    • `: name` создает группу без захвата
      • мнемоника: аналогично (?: ... )
    • `-name` создает обратную ссылку
      • мнемоника: тире соединяет его с предыдущим вхождением
  • переопределяет отдельные символы и использует его везде, если не указано в кавычках
    • здесь разрешены только некоторые символы (например, ~ @ #% ")
      • переопределение + или ( было бы чрезвычайно запутанным, поэтому нельзя
      • переопределить пробел, означающий, что любой интервал очень естественен в примере выше
      • переопределение символа может сделать шаблон более компактным, что хорошо, если не используется чрезмерно
      • , например, использование чего-то вроде define ('#', "\\\\") для сопоставления обратных косых черт может сделать шаблон более читабельным
  • ] переопределите некоторые цитируемые последовательности, такие как \ s или \ w
    • , стандартные определения не соответствуют Unicode
    • иногда у вас может быть собственное представление о том, что такое слово или пробел

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

Вопросы

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

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

.define(' ', "\\s")            // a blank character
.define('~', "/\**[^*]+\*/")   // an inline comment (simplified)
.define("something", "[ ~\\d]")

расширение пространства до \ s имеет смысл, но расширение тильды - нет. Может быть, нужен отдельный синтаксис для того, чтобы каким-то образом определять собственные классы символов?

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

Реакция на ответ Христа

Комментарии к его возражениям

  1. Отсутствие многострочных строк шаблона.
    • В Java нет многострочных строк, которые я бы хотел изменить, но не могу.
  2. Свобода от безумно обременительной и подверженной ошибкам двойной обратной косой черты ...
    • Я снова не могу этого сделать, я могу предложить только обходной путь, s. ниже.
  3. Отсутствие исключений времени компиляции для недопустимых литералов регулярных выражений и отсутствие кэширования во время компиляции правильно скомпилированных литералов регулярных выражений.
    • Поскольку регулярные выражения являются лишь частью стандартной библиотеки, а не самим языком, здесь ничего нельзя сделать.
  4. Никаких средств отладки или профилирования.
    • Ничего не могу поделать
  5. Несоответствие UTS №18.
    • Это можно легко решить, переопределив соответствующие шаблоны, как я предложил. Это не идеально, так как в отладчике вы увидите взорванные замены.

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

RFC 5322

Ваш пример можно легко написать с использованием моего синтаксиса:

final MyPattern pattern = MyPattern.builder()
.define(" ", "") // ignore spaces
.useForBackslash('#') // (1): see (2)
.define("address",         "`mailbox` | `group`")
.define("WSP",             "[\u0020\u0009]")
.define("DQUOTE",          "\"")
.define("CRLF",            "\r\n")
.define("DIGIT",           "[0-9]")
.define("ALPHA",           "[A-Za-z]")
.define("NO_WS_CTL",       "[\u0001-\u0008\u000b\u000c\u000e-\u001f\u007f]") // No whitespace control
...
.define("domain_literal",  "`CFWS`? #[ (?: `FWS`? `dcontent`)* `FWS`? #] `CFWS1?") // (2): see (1)
...
.define("group",           "`display_name` : (?:`mailbox_list` | `CFWS`)? ; `CFWS`?")
.define("angle_addr",      "`CFWS`? < `addr_spec` `CFWS`?")
.define("name_addr",       "`display_name`? `angle_addr`")
.define("mailbox",         "`name_addr` | `addr_spec`")
.define("address",         "`mailbox` | `group`")
.build("`address`");

Недостатки

При переписывании вашего примера я обнаружил следующие проблемы:

  • Поскольку нет \ xdd escape-последовательностей \ udddd необходимо использовать
  • Использование другого символа вместо обратной косой черты немного странно
  • Поскольку я предпочитаю писать его снизу вверх, Мне пришлось вернуть ваши строки
  • Не имея представления о том, что он делает, - Игнорирование пробелов не проблема - Комментарии не проблема - Удобочитаемость

    И самое главное: Это обычная Java и использует существующий механизм регулярных выражений как есть.

7
задан Community 23 May 2017 в 10:33
поделиться