假设我们有以下输入:
<amy>
(bob)
<carol)
(dean>
我们还有以下正则表达式:
<(\w+)>|\((\w+)\)
现在我们得到两个匹配项(如 rubular.com 上所见):
<amy>
是匹配,\1
捕获amy
,\2
失败(bob)
是匹配,\2
捕获bob
,\1
失败
这个正则表达式完成了我们想要的大部分工作,它们是:
- 它正确匹配左括号和右括号(即没有混合)
- 它捕获了我们感兴趣的部分
但是,它确实有一些缺点:
- 重复捕获模式(即“主要”部分)
- 仅
\w+
在这种情况下,但一般来说,这可能非常复杂,- 如果它涉及反向引用,则必须为每个替代项重新编号!
- 重复使维护成为噩梦!(如果它改变了呢?)
- 仅
- 这些组基本上是重复的
- 根据哪些备用匹配,我们必须查询不同的组
- 它只是
\1
或\2
在这种情况下,但通常“主要”部分可以拥有自己的捕获组!
- 它只是
- 这不仅不方便,而且在某些情况下这是不可行的(例如,当我们使用仅限于查询一组的自定义正则表达式框架时)
- 根据哪些备用匹配,我们必须查询不同的组
- 如果我们还想匹配
{...}
,[...]
等,情况会迅速恶化。
所以问题很明显:我们如何在不重复“主要”模式的情况下做到这一点?
注意:在大多数情况下,我对
java.util.regex
风味感兴趣,但也欢迎其他风味。
附录
本节没有新内容;它只是用一个例子来说明上面提到的问题。
让我们把上面的例子带到下一步:我们现在要匹配这些:
<amy=amy>
(bob=bob)
[carol=carol]
但不是这些:
<amy=amy) # non-matching bracket
<amy=bob> # left hand side not equal to right hand side
使用替代技术,我们有以下工作(如 rubular.com 所示):
<((\w+)=\2)>|\(((\w+)=\4)\)|\[((\w+)=\6)\]
如上所述:
- 主要模式不能简单地重复;反向引用必须重新编号
- 如果发生变化,重复也意味着维护噩梦
- 根据备用匹配项,我们必须查询
\1 \2
、\3 \4
或\5 \6