正则表达式的替代(流畅?)接口的设计

sfu*_*ger 27 java regex maintainability fluent-interface readability

我刚刚看到Java的一个巨大的正则表达式让我想到了一般的正则表达式的可维护性.我相信大多数人 - 除了一些坏蛋perl贩子 - 会同意正则表达式难以维持.

我在考虑如何解决这种情况.到目前为止,我最有希望的想法是使用流畅的界面.举个例子,而不是:

Pattern pattern = Pattern.compile("a*|b{2,5}");
Run Code Online (Sandbox Code Playgroud)

一个人可以写这样的东西

import static util.PatternBuilder.*

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();

Pattern alternative = 
  or(
    string("a").anyTimes(),
    string("b").times(2,5)
  )
  .compile();
Run Code Online (Sandbox Code Playgroud)

在这个非常简短的例子中,创建正则表达式的常用方法对于任何平庸的有才华的开发人员来说仍然是可读的.但是,请考虑那些填充两行或更多行的怪异表达式,每行包含80个字符.当然,(冗长)流畅的界面需要几行而不是只有两行,但我相信它会更具可读性(因此可维护).

现在我的问题:

  1. 你知道正则表达式的任何类似方法吗?

  2. 你是否同意这种方法比使用简单的字符串更好?

  3. 你会如何设计API?

  4. 你会在你的项目中使用这样一个整洁的实用程序吗?

  5. 你认为这会很有趣吗?;)

编辑: 想象一下,可能存在比简单构造更高级别的方法,我们都没有来自正则表达式,例如

// matches aaaab@example.com - think of it as reusable expressions
Pattern p = string{"a").anyTimes().string("b@").domain().compile();
Run Code Online (Sandbox Code Playgroud)

编辑 - 评论的简短摘要:

有趣的是,大多数人都认为正则表达式仍然存在 - 虽然它需要工具来阅读它们,聪明的家伙想办法让它们可维护.虽然我不确定流畅的界面是最好的方法,但我确信有些聪明的工程师 - 我们呢?;) - 应该花一些时间让正则表达式成为过去 - 这已经足够让他们和我们在一起已有50年了,你不觉得吗?

开放的BOUNTY

对于正则表达式的新方法,赏金将被授予最佳想法(无需代码).

编辑 - 一个很好的例子:

这是我正在谈论的那种模式 - 对能够翻译它的第一个人的额外荣誉 - RegexBuddies允许(它来自Apache项目btw)授予chiimez的额外荣誉:它是符合RFC的电子邮件地址验证模式 -虽然它的RFC822(参见ex-parrot.com),而不是5322 - 不确定是否存在差异 - 如果是的话,我将为补丁补充下一个额外的荣誉,以适应5322;)

private static final String pattern = "(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:"
    + "\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:("
    + "?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ "
    + "\\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\0"
    + "31]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\"
    + "](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+"
    + "(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:"
    + "(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)"
    + "?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\"
    + "r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?["
    + " \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)"
    + "?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t]"
    + ")*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?["
    + " \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*"
    + ")(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t]"
    + ")+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)"
    + "*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+"
    + "|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r"
    + "\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:"
    + "\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t"
    + "]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031"
    + "]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\]("
    + "?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?"
    + ":(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?"
    + ":\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)|(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?"
    + ":(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?"
    + "[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*:(?:(?:\\r\\n)?[ \\t])*(?:(?:(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|"
    + "\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>"
    + "@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\""
    + "(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?"
    + ":[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\["
    + "\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:[^()<>@,;:\\\".\\[\\] \\000-"
    + "\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|("
    + "?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)?[ \\t])*(?:@(?:[^()<>@,;"
    + ":\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[(["
    + "^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\""
    + ".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\"
    + "]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\"
    + "[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\"
    + "r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] "
    + "\\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]"
    + "|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?(?:[^()<>@,;:\\\".\\[\\] \\0"
    + "00-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\"
    + ".|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,"
    + ";:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\"(?"
    + ":[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*))*@(?:(?:\\r\\n)?[ \\t])*"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t])*(?:["
    + "^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]"
    + "]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:(?:\\r\\n)?[ \\t])*)(?:,\\s*("
    + "?:(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:("
    + "?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=["
    + "\\[\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t"
    + "])*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t"
    + "])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?"
    + ":\\.(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|"
    + "\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*|(?:"
    + "[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\"
    + "]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)*\\<(?:(?:\\r\\n)"
    + "?[ \\t])*(?:@(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\""
    + "()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)"
    + "?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>"
    + "@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*(?:,@(?:(?:\\r\\n)?["
    + " \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,"
    + ";:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:\\r\\n)?[ \\t]"
    + ")*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\\"
    + "\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*)*:(?:(?:\\r\\n)?[ \\t])*)?"
    + "(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\[\"()<>@,;:\\\"."
    + "\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])*)(?:\\.(?:(?:"
    + "\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z|(?=[\\["
    + "\"()<>@,;:\\\".\\[\\]]))|\"(?:[^\\\"\\r\\\\]|\\\\.|(?:(?:\\r\\n)?[ \\t]))*\"(?:(?:\\r\\n)?[ \\t])"
    + "*))*@(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])"
    + "+|\\Z|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*)(?:\\"
    + ".(?:(?:\\r\\n)?[ \\t])*(?:[^()<>@,;:\\\".\\[\\] \\000-\\031]+(?:(?:(?:\\r\\n)?[ \\t])+|\\Z"
    + "|(?=[\\[\"()<>@,;:\\\".\\[\\]]))|\\[([^\\[\\]\\r\\\\]|\\\\.)*\\](?:(?:\\r\\n)?[ \\t])*))*\\>(?:("
    + "?:\\r\\n)?[ \\t])*))*)?;\\s*)";
Run Code Online (Sandbox Code Playgroud)

Dom*_*nik 19

Martin Fowler提出了另一种策略.即采用正则表达式的有意义部分并用变量替换它们.他使用以下示例:

 "^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*)" 
Run Code Online (Sandbox Code Playgroud)

   String scoreKeyword = "^score\s+";
   String numberOfPoints = "(\d+)";
   String forKeyword = "\s+for\s+";
   String numberOfNights = "(\d+)";
   String nightsAtKeyword = "\s+nights?\s+at\s+";
   String hotelName = "(.*)";

   String pattern = scoreKeyword + numberOfPoints +
      forKeyword + numberOfNights + nightsAtKeyword + hotelName;
Run Code Online (Sandbox Code Playgroud)

哪个更具可读性和可维护性.

上一个示例的目标是从字符串列表中解析numberOfPoints,numberOfNights和hotelName,如:

score 400 for 2 nights at Minas Tirith Airport
Run Code Online (Sandbox Code Playgroud)


Jer*_*ein 18

没有任何正则表达式经验的人可能会稍微容易些,但是在有人学习你的系统之后,他仍然无法在其他地方阅读正常的正则表达式.

此外,我认为您的版本更难以阅读正则表达式专家.

我建议像这样注释正则表达式:

Pattern pattern = Pattern.compile(
  "a*     # Find 0 or more a        \n" +
  "|      # ... or ...              \n" +
  "b{2,5} # Find between 2 and 5 b  \n",
Pattern.COMMENTS);
Run Code Online (Sandbox Code Playgroud)

这对于任何经验水平都很容易阅读,对于没有经验的人来说,它同时教授正则表达式.此外,评论可以根据情况进行调整,以解释正则表达式背后的业务规则,而不仅仅是结构.

此外,像RegexBuddy这样的工具可以将你的正则表达式转换为:

Match either the regular expression below (attempting the next alternative only if this one fails) «a*»
   Match the character "a" literally «a*»
      Between zero and unlimited times, as many times as possible, giving back as needed (greedy) «*»
Or match regular expression number 2 below (the entire match attempt fails if this one fails to match) «b{2,5}»
   Match the character "b" literally «b{2,5}»
      Between 2 and 5 times, as many times as possible, giving back as needed (greedy) «{2,5}»

  • 没有机会让正则表达式很快成为过去的事情.它们对于文本解析来说太有用了,没有好的选择. (4认同)
  • 好点子.但是,我喜欢将正则表达式视为过去 - 所以不需要学习它或教任何人.只是让它过时了...请:)你的评论激励我添加一个"编辑:".读取不是由构造构造而是在语义上构造的表达式不是很好.通常你不像在使用正则表达式的语义那样关心使用的构造,对吧? (2认同)

EmF*_*mFi 10

这是一个有趣的概念,但正如它所呈现的那样,存在一些缺陷.

但首先回答的关键问题是:

现在我的问题:

你知道正则表达式的任何类似方法吗?

没有人已经提到过.通过阅读问题和答案,我发现了那些.

你是否同意这种方法比使用简单的字符串更好?

如果它像宣传的那样工作,那肯定会让事情变得更容易调试.

3.您将如何设计API?

请参阅下一节中的我的笔记.我以您的示例和链接的.NET库为出发点.

你会在你的项目中使用这样一个整洁的实用工具吗?

犹豫不决.使用当前版本的隐秘的常规表达式没有问题.我需要一个工具将现有的正则表达式转换为流利的语言版本.

你认为这会很有趣吗?;)

我喜欢编写更高级别的方法,而不是编写实际的代码.这解释了这个答案的文本墙.


以下是我注意到的一些问题,以及我处理它的方式.

结构不清楚.

您的示例似乎通过连接到字符串来创建正则表达式.这不是很强大.我相信这些方法应该添加到String和Patern/Regex对象中,因为它会使实现和代码更清晰.此外,它类似于正则表达式的经典定义方式.

仅仅因为我看不到它以任何其他方式工作,我对提议方案的其余注释将假设所有方法都作用于并返回Pattern对象.

编辑:我似乎始终使用以下约定.所以我澄清了它们并将它们移到了这里.

  • 实例方法:模式扩充.例如:捕获,重复,查看断言.

  • 运营商:运营秩序.交替,连接

  • 常量:字符类,边界(代替\ w,$,\ b等)

如何处理捕获/群集?

捕获是正则表达式的重要组成部分.

我看到每个Pattern对象都在内部存储为一个集群.Perl术语中的(?:pattern).允许图案令牌易于混合和混合而不会干扰其他部件.

我希望捕获作为Pattern上的实例方法完成.采用变量来存储匹配的字符串[s].

pattern.capture(variable)将模式存储在变量中.如果捕获是要多次匹配的表达式的一部分,则变量应包含模式的所有匹配的字符串数组.

流利的语言可能非常模糊.

流利的语言不太适合正则表达式的递归性质.因此需要考虑操作的顺序.仅将方法链接在一起不允许非常复杂的正则表达式.究竟是这种工具有用的情况.

是否

Pattern pattern = string("a").anyTimes().or().string("b").times(2,5).compile();
Run Code Online (Sandbox Code Playgroud)

生产/a*|b{2,5}//(a*|b){2,5}/

这样的方案如何处理嵌套交替?例如:/a*|b(c|d)|e/

我在正则表达式中看到了三种处理交替的方法

  1. 作为运营商: pattern1 or pattern2 => pattern # /pattern1|pattern2/
  2. 作为一种类方法: Pattern.or( pattern1, pattern2[, pattern3]*) => pattern # /pattern1|patern2|patern3|...|/
  3. 作为实例方法: pattern1.or(pattern2) => pattern # /pattern1|patern2/

我会以同样的方式处理串联.

  1. 作为运营商: pattern1 + pattern2 => pattern # /pattern1pattern2/
  2. 作为一种类方法: Pattern.concatenate( pattern1, pattern2[, pattern3]*) => pattern # /pattern1patern2patern3.../
  3. 作为实例方法: pattern1.then(pattern2) => pattern # /pattern1patern2/

如何扩展常用模式

使用的提议方案.domain()似乎是一个普通的正则表达式.将用户定义的模式视为方法不会使添加新模式变得容易.在像Java这样的语言中,库的用户必须重写类以添加常用模式的方法.

我的建议是将每件作品作为对象来解决.可以为每个常用的正则表达式创建模式对象,例如匹配域.鉴于我之前关于捕获它的想法并不难以确保捕获适用于包含捕获部分的相同公共模式的多个副本.

对于各种字符类匹配的模式也应该有常量.

零宽度查看断言

扩展我的想法,所有部分都应该隐式聚类.查看断言对于实例方法也不应该太难.

pattern.zeroWidthLookBehind()会产生(?<patten).


还需要考虑的事情.

  • 反向引用:希望对前面讨论过的命名捕获并不太难
  • 如何实际实现它.我没有太多考虑内部因素.这是真正的魔法将要发生的地方.
  • 翻译:确实应该有一个工具转换为经典正则表达式(比如Perl方言)和新方案.从新计划转换可能是一揽子计划的一部分

总而言之,我建议的与电子邮件地址匹配的模式版本:

Pattern domain_label = LETTER_CHARACTER + (LETTER_CHARACTER or "-" or DIGIT_CHARACTER).anyTimes()
Pattern domain = domain_label + ("." + domain_label).anyTimes()
Pattern pattern = (LETTER_CHARACTER + ALPHANUMERIC_CHARACTER + "@" + domain).compile
Run Code Online (Sandbox Code Playgroud)

事后看来,我的计划大量借鉴了Martin Fowler的使用方法.虽然我并不打算采用这种方式,但它确实使得使用这样的系统更易于维护.它还通过福勒的方法(捕获顺序)解决了一两个问题.


RMo*_*sey 7

你会如何设计API?

我会从Hibernate标准API中借用一个页面.而不是使用:

string("a").anyTimes().or().string("b").times(2,5).compile()
Run Code Online (Sandbox Code Playgroud)

使用如下模式:

Pattern.or(Pattern.anyTimes("a"), Pattern.times("b", 2, 5)).compile()
Run Code Online (Sandbox Code Playgroud)

这种表示法更简洁,我觉得理解模式的层次结构/结构更容易.每个方法都可以接受字符串或模式片段作为第一个参数.

你知道正则表达式的任何类似方法吗?

没有随便,没有.

你是否同意这种方法比使用简单的字符串更好?

是的,绝对的...如果你正在使用正则表达式来处理任何远程复杂的东西.对于非常简短的情况,字符串更方便.

你会在你的项目中使用这样一个整洁的实用程序吗?

可能,因为它已被证明/稳定...将它滚动到像Apache Commons这样的大型实用程序项目可能是一个加分.

你认为这会很有趣吗?;)

+1


cod*_*box 7

我自己的卑微尝试可以在GitHub找到.虽然我认为它不值得用于简单的表达式,但除了可读性改进之外,它确实提供了一些优点:

  • 它负责括号匹配
  • 它可以处理所有"特殊"字符的转义,这些字符很快就会导致反斜杠地狱

一些简单的例子:

 // Matches a single digit
    RegExBuilder.build(anyDigit()); // "[0-9]"

 // Matches exactly 2 digits
    RegExBuilder.build(exactly(2).of(anyDigit())); // "[0-9]{2}"

 // Matches between 2 and 4 letters
    RegExBuilder.build(between(2,4).of(anyLetter())); // "[a-zA-Z]{2,4}"
Run Code Online (Sandbox Code Playgroud)

更复杂的一个(或多或少验证电子邮件地址):

final Token ALPHA_NUM = anyOneOf(range('A','Z'), range('a','z'), range('0','9'));
final Token ALPHA_NUM_HYPEN_UNDERSCORE = anyOneOf(characters('_','-'), range('A','Z'), range('a','z'), range('0','9'));

String regexText = RegExBuilder.build(
 // Before the '@' symbol we can have letters, numbers, underscores and hyphens anywhere
    oneOrMore().of(
        ALPHA_NUM_HYPEN_UNDERSCORE
    ),
    zeroOrMore().of(
        text("."), // Periods are also allowed in the name, but not as the initial character
        oneOrMore().of(
            ALPHA_NUM_HYPEN_UNDERSCORE
        )
    ),
    text("@"),
 // Everything else is the domain name - only letters, numbers and periods here
    oneOrMore().of( 
        ALPHA_NUM
    ),
    zeroOrMore().of(
        text("."), // Periods must not be the first character in the domain
        oneOrMore().of(
            ALPHA_NUM
        )
    ),
    text("."), // At least one period is required
    atLeast(2).of( // Period must be followed by at least 2 letters (this is the TLD)
        anyLetter()
    )
);
Run Code Online (Sandbox Code Playgroud)


eld*_*rge 6

.NET 有一个流畅的regexps库.

  • 哦,劳迪,那段代码让我眼前一亮.:( (2认同)