组合(OR)任意正则表达式

CAF*_*FxX 6 java regex optimization

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


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

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

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

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

OR组合正则表达式的显而易见的方法很明显,(regex1)|(regex2)|(regex3)|...|(regexN)但我很确定这不是正确的事情,因为我无法控制单个正则表达式(例如,它们可以包含所有后向/前向引用的方式).因此,我想知道你是否可以建议一种更好的方法来组合java中的任意正则表达式.


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

Mar*_*der 4

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

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

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

所以基本上,对于每个输入模式,您都创建一个唯一的标识符(例如增加一个 ID)。然后最棘手的部分是在模式中找到捕获组。您将无法使用正则表达式来做到这一点。您必须自己解析该模式。如果您只是迭代模式字符串,以下是一些需要注意的事项:

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

一旦您对每个输入模式执行了此操作,您就可以安全地将它们全部与 组合起来|。除反向引用之外的任何其他功能都不会导致此方法出现问题。至少只要你的模式有效就不会。当然,如果你有输入a(bc)d那么你就会遇到问题。但是,如果您不检查模式是否可以自行编译,那么您将始终遇到这种情况。

我希望这能为您指明正确的方向。