Мне нужна помощь, чтобы дополнить мое представление о регулярных выражениях.
Был вопрос о лучшем синтаксисе для регулярных выражений в 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
Именованные шаблоны служат своего рода локальными переменными, помогая разложить сложное выражение на небольшие и простые для понимания части. Правильный шаблон именования часто делает комментарий ненужным.
Вышесказанное не должно быть трудным для реализации (я уже сделал большую часть из этого) и может быть действительно полезным, я надеюсь. Вы так думаете?
Однако я не уверен, как он должен вести себя внутри скобок, иногда имеет смысл использовать определения, а иногда нет, например, в
.define(' ', "\\s") // a blank character
.define('~', "/\**[^*]+\*/") // an inline comment (simplified)
.define("something", "[ ~\\d]")
расширение пространства до \ s
имеет смысл, но расширение тильды - нет.
Может быть, нужен отдельный синтаксис для того, чтобы каким-то образом определять собственные классы символов?
Можете ли вы вспомнить несколько примеров, в которых именованный шаблон очень полезен или совсем не полезен? Мне понадобятся некоторые пограничные случаи и некоторые идеи для улучшения.
Похоже, вам не нравится Java. Я был бы рад увидеть там некоторые улучшения синтаксиса, но я ничего не могу с этим поделать. Я ищу что-нибудь, работающее с текущей Java.
Ваш пример можно легко написать с использованием моего синтаксиса:
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 и использует существующий механизм регулярных выражений как есть.