gpt4 book ai didi

java - 更好的正则表达式语法想法

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:31:12 24 4
gpt4 key购买 nike

我需要一些帮助来完成我对正则表达式的想法。

介绍

有一个 question about better syntax对于 SE 上的正则表达式,但我认为我不会使用流畅的语法。
这对新手来说肯定很好,但在复杂的正则表达式的情况下,
你用一整页稍微好一点的胡言乱语替换一行胡言乱语。
我喜欢 approach by 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

其中 fluent 语法用于组合扩展如下的正则表达式:
  • 定义命名模式并通过用反引号括起来来使用它们
  • `name`创建一个命名组
  • 助记符:shell 捕获用反引号括起来的命令的结果
  • `:name`创建一个非捕获组
  • 助记符:类似于 (?: ... )
  • `-name`创建反向引用
  • 助记符:破折号将它连接到上一个事件
  • 重新定义单个字符并在任何地方使用它,除非引用
  • 这里只允许使用一些字符(例如,~ @#% ")
  • 重新定义 +(会非常困惑,所以不允许
  • 在上面的示例中,重新定义空间以表示任何间距是非常自然的
  • 重新定义一个字符可以使模式更紧凑,除非过度使用,否则这很好
  • 例如,使用类似 define('#', "\\\\") 的东西匹配反斜杠可以使模式更具可读性
  • 重新定义一些引用序列,如 \s\w
  • 标准定义是 not Unicode conform
  • 有时您可能有自己的想法

  • 命名模式充当一种局部变量,有助于将复杂的表达式分解为小而易于理解的部分。
    正确的命名模式通常会使注释变得不必要。

    问题

    以上应该不难实现(我已经做了大部分)并且可能非常有用,我希望。
    你是这样认为的吗?

    但是,我不确定它在括号内应该如何表现,有时使用定义有意义,有时则没有,例如在
    .define(' ', "\\s")            // a blank character
    .define('~', "/\**[^*]+\*/") // an inline comment (simplified)
    .define("something", "[ ~\\d]")

    扩大空间到 \s有道理,但扩展波浪号没有。
    也许应该有一个单独的语法来以某种方式定义自己的字符类?

    你能想出一些例子,其中命名模式非常有用或根本没有用吗?
    我需要一些边界案例和一些改进的想法。

    对基督的回答的 react

    对他的反对意见的评论
  • 缺少多行模式字符串。
  • Java 中没有多行字符串,我想更改,但不能。
  • 免于极其繁琐且容易出错的双重反斜杠...
  • 这又是我不能做的事情,我只能提供一个解决方法,s。以下。
  • 缺少对无效正则表达式文本的编译时异常,并且缺少正确编译的正则表达式文本的编译时缓存。
  • 由于正则表达式只是标准库的一部分而不是语言本身,因此这里无能为力。
  • 没有调试或分析工具。
  • 我在这里无能为力。
  • 不符合 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转义序列 \udddd必须使用
  • 使用另一个字符代替反斜杠有点奇怪
  • 因为我更喜欢自下而上写,所以我不得不把你的台词还原
  • 不太了解它的作用,除了我自己犯了一些错误

  • 在亮的一边:
    - 忽略空格没问题
    - 评论没问题
    - 可读性好

    最重要的是: 它是纯 Java 并按原样使用现有的正则表达式引擎。

    最佳答案

    命名捕获示例

    Can you think of some examples where the named pattern are very useful or not useful at all?



    为了回答您的问题,这里有一个示例,其中命名模式特别有用。它是用于解析 RFC 5322 邮件地址的 Perl 或 PCRE 模式。首先,它在 /x模式凭借 (?x) .其次,它将定义与调用分开;命名组 address是进行完整递归下降解析的东西。它的定义在非执行 (?DEFINE)…) 中遵循它堵塞。
       (?x)              # allow whitespace and comments

    (?&address) # this is the capture we call as a "regex subroutine"

    # the rest is all definitions, in a nicely BNF-style
    (?(DEFINE)

    (?<address> (?&mailbox) | (?&group))
    (?<mailbox> (?&name_addr) | (?&addr_spec))
    (?<name_addr> (?&display_name)? (?&angle_addr))
    (?<angle_addr> (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
    (?<group> (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
    (?<display_name> (?&phrase))
    (?<mailbox_list> (?&mailbox) (?: , (?&mailbox))*)

    (?<addr_spec> (?&local_part) \@ (?&domain))
    (?<local_part> (?&dot_atom) | (?&quoted_string))
    (?<domain> (?&dot_atom) | (?&domain_literal))
    (?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
    \] (?&CFWS)?)
    (?<dcontent> (?&dtext) | (?&quoted_pair))
    (?<dtext> (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

    (?<atext> (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
    (?<atom> (?&CFWS)? (?&atext)+ (?&CFWS)?)
    (?<dot_atom> (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
    (?<dot_atom_text> (?&atext)+ (?: \. (?&atext)+)*)

    (?<text> [\x01-\x09\x0b\x0c\x0e-\x7f])
    (?<quoted_pair> \\ (?&text))

    (?<qtext> (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
    (?<qcontent> (?&qtext) | (?&quoted_pair))
    (?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
    (?&FWS)? (?&DQUOTE) (?&CFWS)?)

    (?<word> (?&atom) | (?&quoted_string))
    (?<phrase> (?&word)+)

    # Folding white space
    (?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
    (?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
    (?<ccontent> (?&ctext) | (?&quoted_pair) | (?&comment))
    (?<comment> \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
    (?<CFWS> (?: (?&FWS)? (?&comment))*
    (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

    # No whitespace control
    (?<NO_WS_CTL> [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

    (?<ALPHA> [A-Za-z])
    (?<DIGIT> [0-9])
    (?<CRLF> \x0d \x0a)
    (?<DQUOTE> ")
    (?<WSP> [\x20\x09])
    )

    我强烈建议不要重新发明一个完美的轮子。从成为 PCRE 兼容开始。如果你想超越基本的 Perl5 模式,比如上面的 RFC5322 解析器,总是有 Perl6 patterns借鉴。

    真的,真的在开始一项开放式的研发任务之前,对现有的实践和文献进行研究是值得的。这些问题早就被解决了,有时还很优雅。

    改进 Java 正则表达式语法

    如果你真的想要更好的 Java 正则表达式语法想法,你必须首先解决 Java 正则表达式中的这些特定缺陷:
  • 缺少多行模式字符串,如上所示。
  • 如上所述,无需使用极其繁琐且容易出错的双反斜杠。
  • 缺少对无效正则表达式文本的编译时异常,并且缺少正确编译的正则表达式文本的编译时缓存。
  • 无法更改类似 "foo".matches(pattern) 的内容使用更好的模式库,部分但不完全是因为 final不可覆盖的类。
  • 没有调试或分析工具。
  • 不符合 UTS#18: Basic Regular Expression support ,使 Java 正则表达式对 Unicode 有用所需的最基本步骤。他们目前不是。它们甚至不支持十年前的 Unicode 3.1 属性,这意味着您不能以任何合理的方式为 Unicode 使用 Java 模式;没有基本的构建块。

  • 其中,前 3 种语言已在多种 JVM 语言中得到解决,包括 Groovy 和 Scala;甚至 Clojure 也半途而废。

    第二组 3 个步骤将更加艰难,但绝对是强制性的。最后一个,在正则表达式中甚至连最基本的 Unicode 支持都没有,只是为了 Unicode 工作而扼杀了 Java。这在游戏后期是完全不可原谅的。如果需要,我可以提供大量示例,但您应该相信我,因为我真的知道我在这里谈论的是什么。

    只有在完成所有这些之后,您才应该担心修复 Java 的正则表达式,以便它们能够 catch 模式匹配的当前技术水平。除非您处理这些过去的疏忽,否则您无法开始关注现在,更不用说 future 了。

    关于java - 更好的正则表达式语法想法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4914774/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com