【问题标题】:Combining (OR) arbitrary regular expressions组合 (OR) 任意正则表达式
【发布时间】:2012-12-03 03:32:09
【问题描述】:

tl;dr 有没有办法在 Java 中将任意正则表达式或/组合成一个正则表达式(用于匹配,而不是捕获)?


在我的应用程序中,我收到了来自用户的两个列表:

  1. 正则表达式列表
  2. 字符串列表

我需要输出 (2) 中与 (1) 中的任何正则表达式都不匹配的字符串列表。

我有明显的幼稚实现(迭代(2)中的所有字符串;对于每个字符串迭代(1)中的所有模式;如果没有模式匹配,则将字符串添加到将返回的列表中)但是我想知道是否可以将所有模式组合成一个模式并让正则表达式编译器利用优化机会。

OR-组合正则表达式的明显方法显然是(regex1)|(regex2)|(regex3)|...|(regexN),但考虑到我无法控制单个正则表达式,我很确定这不是正确的做法(例如,它们可以包含所有方式的 back/前向参考)。因此,我想知道您是否可以提出一种在 java 中组合任意正则表达式的更好方法。


注意:这只是上面的暗示,但我会明确表示:我只匹配字符串 - 我不需要使用捕获组的输出。

【问题讨论】:

  • 一个正则表达式是只匹配部分字符串还是匹配整个字符串?
  • @Tomalak 应该允许用户提供的正则表达式匹配 (2) 中的部分字符串 - 特别是在天真的实现中,我使用 Matcher.find() 来查看是否至少有一个匹配项
  • 您认为regex1|regex2|regex3 产生错误结果的原因是什么?你能构建一个它会的情况吗?
  • 我明白了。是的,有了反向引用,你就永远不走运了。不能组合自引用表达式。
  • @Tomalak 一些引擎提供(?|...|...|...),其中每个替代方案的组从1 开始计算......但不幸的是,我认为Java 没有

标签: java regex optimization


【解决方案1】:

一些正则表达式引擎(例如 PCRE)具有构造 (?|...)。它就像一个非捕获组,但具有一个很好的功能,即在每个交替组中都从相同的初始值开始计数。这可能会立即解决您的问题。因此,如果您可以选择为此任务切换语言,那应该可以解决问题。

[edit: 事实上,它仍然会导致与named 捕获组发生冲突的问题。事实上,该模式甚至无法编译,因为组名无法重复使用。]

否则您将不得不操纵输入模式。 hyde 建议重新编号反向引用,但我认为有一个更简单的选择:将所有组命名为组。您可以向自己保证这些名称是独一无二的。

所以基本上,对于每个输入模式,您都会创建一个唯一标识符(例如,增加一个 ID)。然后最棘手的部分是在模式中找到捕获组。您将无法使用正则表达式执行此操作。您必须自己解析模式。如果您只是简单地遍历模式字符串,以下是一些关于要注意什么的想法:

  • 进入和离开字符类时请注意,因为字符类内部的括号是文字字符。
  • 也许是最棘手的部分:忽略后面跟着?:、?=、?!、?<=、?<!、?> 的所有左括号。此外,还有选项设置括号:(?idmsuxU-idmsuxU) 或 (?idmsux-idmsux:somePatternHere),它们也不会捕获任何内容(当然,这些选项可以是任何子集,并且它们可以按任何顺序排列 - - 也是可选的)。李>
  • 现在您应该只剩下左括号,它们可以是普通捕获组或命名为:(?<name>。最简单的方法可能是对它们一视同仁——即同时具有数字和名称(如果未设置名称,则名称等于数字)。然后你用(?<uniqueIdentifier-md5hashOfName>之类的东西重写所有这些(连字符实际上不能是名称的一部分,你只会有你的递增数字后跟散列 - 因为散列是固定长度的,所以不会有任何重复;至少差不多)。请务必记住该组最初的编号和名称。
  • 每当遇到反斜杠时,都有三个选项:
    1. 下一个字符是一个数字。你有一个编号的反向引用。用k<name> 替换所有这些数字,其中name 是您为该组生成的新组名。
    2. 接下来的字符是k<...>。再次将其替换为相应的新名称。
    3. 下一个字符是其他字符。跳过它。它同时处理括号转义和反斜杠转义。
  • 我认为 Java 可能允许前向引用。在这种情况下,您需要两次通过。首先要重命名所有组。然后更改所有引用。

在每个输入模式上完成此操作后,您就可以安全地将所有输入模式与| 结合起来。除了反向引用之外的任何其他功能都不应导致此方法出现问题。至少只要你的模式是有效的。当然,如果你有输入 a(b 和 c)d 那么你就有问题了。但是,如果您不检查模式是否可以自行编译,您将始终拥有这种情况。

我希望这能给你指明正确的方向。

【讨论】:

    猜你喜欢
    • 2011-06-23
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-17
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多