一些正则表达式引擎(例如 PCRE)具有结构(?|...)
. 它就像一个非捕获组,但具有一个很好的功能,即在每个交替组中都从相同的初始值开始计数。这可能会立即解决您的问题。因此,如果您可以选择为此任务切换语言,那应该可以解决问题。
[编辑:事实上,它仍然会导致命名捕获组冲突的问题。事实上,该模式甚至无法编译,因为组名不能被重用。]
否则,您将不得不操纵输入模式。hyde 建议重新编号反向引用,但我认为有一个更简单的选择:将所有组命名为组。您可以向自己保证,这些名称是独一无二的。
所以基本上,对于每个输入模式,您都会创建一个唯一标识符(例如,增加一个 ID)。然后最棘手的部分是在模式中找到捕获组。您将无法使用正则表达式执行此操作。您必须自己解析模式。如果您只是简单地遍历模式字符串,这里有一些关于要注意什么的想法:
- 进入和离开字符类时请注意,因为字符类内部的括号是文字字符。
- 也许是最棘手的部分:忽略所有后跟
?:
, ?=
, ?!
, ?<=
, ?<!
,的左括号?>
。此外,还有选项设置括号:(?idmsuxU-idmsuxU)
或者(?idmsux-idmsux:somePatternHere)
也没有捕获任何内容(当然可以有这些选项的任何子集,并且它们可以按任何顺序排列 --
也是可选的)。
- 现在你应该只剩下左括号了,它们要么是普通的捕获组,要么是命名的 on:
(?<name>
。最简单的方法可能是对它们一视同仁——即同时具有数字和名称(如果未设置名称,则名称等于数字)。然后你用类似的东西重写所有这些(?<uniqueIdentifier-md5hashOfName>
(连字符实际上不能是名称的一部分,你只会有你的递增数字后跟散列 - 因为散列是固定长度的,所以不会有任何重复;几乎在至少)。确保记住该组最初的编号和名称。
- 每当遇到反斜杠时,都有三个选项:
- 下一个字符是一个数字。你有一个编号的反向引用。将所有这些数字替换为
k<name>
您name
为该组生成的新组名。
- 下一个字符是
k<...>
. 再次将其替换为相应的新名称。
- 下一个字符是别的。跳过它。它同时处理括号的转义和反斜杠的转义。
- 我认为Java可能允许前向引用。在这种情况下,您需要两次通过。首先要重命名所有组。然后更改所有引用。
一旦对每个输入模式都完成了此操作,您就可以安全地将所有输入模式与|
. 除了反向引用之外的任何其他功能都不应导致此方法出现问题。至少只要你的模式是有效的。当然,如果你有输入a(b
,c)d
那么你就有问题了。但是,如果您不检查模式是否可以自行编译,您将始终拥有它。
我希望这可以为您指明正确的方向。