我需要一些帮助才能完成关于正则表达式的想法.
关于SE上正则表达式的更好语法有一个问题,但我认为我不会使用流畅的语法.这对新手来说肯定不错,但是如果是复杂的正则表达式,你会用一整页稍微好一点的胡言乱语来代替一行乱码.我喜欢Martin Fowler的方法,其中正则表达式由较小的部分组成.他的解决方案是可读的,但手工制作; 他提出了一种聪明的方法来构建复杂的正则表达式而不是支持它的类.
我正试图用类似的东西来上课(首先看他的例子)
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
Run Code Online (Sandbox Code Playgroud)
其中fluent语法用于组合扩展的regex,如下所示:
`name` 创建一个命名组
`:name` 创建一个非捕获组
(?:......)`-name` 创建一个反向引用
~ @#%")"
+或(将是非常混乱,所以这是不允许的define('#', "\\\\")匹配反斜杠的东西可以使图案更具可读性\s或\w
命名模式用作一种局部变量,有助于将复杂的表达式分解为小而易于理解的部分.正确的命名模式通常不需要注释.
我希望上面的内容不应该很难实现(我已经完成了大部分工作)并且可能非常有用. 你这么认为吗?
但是,我不确定它应该如何在括号内表现,有时使用定义是有意义的,有时候不是,例如
.define(' ', "\\s") // a blank character
.define('~', "/\**[^*]+\*/") // an inline comment (simplified)
.define("something", "[ ~\\d]")
Run Code Online (Sandbox Code Playgroud)
扩大空间\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`");
Run Code Online (Sandbox Code Playgroud)
在重写您的示例时,我遇到了以下问题:
\xdd转义序列\udddd好的一面: - 忽略空间没问题 - 评论没问题 - 可读性好
最重要的是:它是普通的Java并且使用现有的正则表达式引擎.
\n\n\n您能想出一些示例,其中命名模式非常有用或根本没有用吗?
\n
为了回答您的问题,这里有一个示例,其中命名模式特别有用。它\xe2\x80\x99是用于解析RFC 5322邮件地址的Perl或PCRE模式。首先,它\xe2\x80\x99s/x凭借(?x). 其次,它将定义与调用分开;命名组address是执行完整递归下降解析的东西。它的定义遵循非执行(?DEFINE)\xe2\x80\xa6)块中的定义。
(?x) # allow whitespace and comments\n\n (?&address) # this is the capture we call as a "regex subroutine"\n\n # the rest is all definitions, in a nicely BNF-style\n (?(DEFINE)\n\n (?<address> (?&mailbox) | (?&group))\n (?<mailbox> (?&name_addr) | (?&addr_spec))\n (?<name_addr> (?&display_name)? (?&angle_addr))\n (?<angle_addr> (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)\n (?<group> (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)\n (?<display_name> (?&phrase))\n (?<mailbox_list> (?&mailbox) (?: , (?&mailbox))*)\n\n (?<addr_spec> (?&local_part) \\@ (?&domain))\n (?<local_part> (?&dot_atom) | (?"ed_string))\n (?<domain> (?&dot_atom) | (?&domain_literal))\n (?<domain_literal> (?&CFWS)? \\[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?\n \\] (?&CFWS)?)\n (?<dcontent> (?&dtext) | (?"ed_pair))\n (?<dtext> (?&NO_WS_CTL) | [\\x21-\\x5a\\x5e-\\x7e])\n\n (?<atext> (?&ALPHA) | (?&DIGIT) | [!#\\$%&\'*+-/=?^_`{|}~])\n (?<atom> (?&CFWS)? (?&atext)+ (?&CFWS)?)\n (?<dot_atom> (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)\n (?<dot_atom_text> (?&atext)+ (?: \\. (?&atext)+)*)\n\n (?<text> [\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])\n (?<quoted_pair> \\\\ (?&text))\n\n (?<qtext> (?&NO_WS_CTL) | [\\x21\\x23-\\x5b\\x5d-\\x7e])\n (?<qcontent> (?&qtext) | (?"ed_pair))\n (?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*\n (?&FWS)? (?&DQUOTE) (?&CFWS)?)\n\n (?<word> (?&atom) | (?"ed_string))\n (?<phrase> (?&word)+)\n\n # Folding white space\n (?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)\n (?<ctext> (?&NO_WS_CTL) | [\\x21-\\x27\\x2a-\\x5b\\x5d-\\x7e])\n (?<ccontent> (?&ctext) | (?"ed_pair) | (?&comment))\n (?<comment> \\( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \\) )\n (?<CFWS> (?: (?&FWS)? (?&comment))*\n (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))\n\n # No whitespace control\n (?<NO_WS_CTL> [\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f])\n\n (?<ALPHA> [A-Za-z])\n (?<DIGIT> [0-9])\n (?<CRLF> \\x0d \\x0a)\n (?<DQUOTE> ")\n (?<WSP> [\\x20\\x09])\n )\nRun Code Online (Sandbox Code Playgroud)\n\n我强烈建议不要重新发明一个完美的轮子。从兼容 PCRE 开始。如果您希望超越基本的 Perl5 模式(如上面的 RFC5322 解析器),则始终可以利用\xe2\x80\x99s Perl6 模式。
\n\n在开始一项开放式研发任务之前,对现有实践和文献进行研究确实非常值得。这些问题早已得到解决,有时甚至相当优雅。
\n\n如果您确实想要更好的 Java 正则表达式语法想法,则必须首先解决 Java\xe2\x80\x99s 正则表达式中的这些特定缺陷:
\n\n"foo".matches(pattern)使用更好的模式库,部分原因但不仅仅是因为final类不可重写。其中,前 3 个已在多种 JVM 语言中得到解决,包括 Groovy 和 Scala;甚至 Clojure 也只做到了这一点。
\n\n第二组 3 个步骤会更困难,但绝对是强制性的。最后一个,正则表达式中甚至缺乏最基本的 Unicode 支持,只会扼杀 Java 的 Unicode 工作。在比赛的后期,这是完全不可原谅的。如果需要的话,我可以提供很多例子,但你应该相信我,因为我真的知道我\xe2\x80\x99m在这里谈论的是什么。
\n\n只有完成所有这些后,您才应该担心修复 Java\xe2\x80\x99s 正则表达式,以便它们能够赶上模式匹配的当前技术水平。除非你解决了过去的这些疏忽,否则你无法开始展望现在,更不用说展望未来了。
\n