假设我们有以下输入:
<amy>
(bob)
<carol)
(dean>
我们还有以下正则表达式:
<(\w+)>|\((\w+)\)
现在我们得到两场比赛(如 rubular.com 上所示 http://www.rubular.com/r/nfwk7d5YRG):
-
<amy>
是一场比赛,\1
捕获amy
, \2
fails
-
(bob)
是一场比赛,\2
捕获bob
, \1
fails
这个正则表达式完成了我们想要的大部分功能,它们是:
- 它正确匹配左括号和右括号(即没有混合)
- 它捕获了我们感兴趣的部分
然而,它确实有一些缺点:
- The capturing pattern (i.e. the "main" part) is repeated
- It's only
\w+
in this case, but generally speaking this can be quite complex,
- 如果涉及反向引用,那么必须为每个替代项重新编号!
- 重复使维护成为一场噩梦! (如果改变怎么办?)
- The groups are essentially duplicated
- Depending on which alternate matches, we must query different groups
- 这只是
\1
or \2
在这种情况下,但通常“主要”部分可以有自己的捕获组!
- 这不仅不方便,而且在某些情况下这是不可行的(例如,当我们使用仅限于查询一组的自定义正则表达式框架时)
- 如果我们也想匹配的话情况很快就会恶化
{...}
, [...]
, etc.
那么问题就很明显了:我们怎样才能在不重复“主要”模式的情况下做到这一点?
注意:大多数情况下我感兴趣java.util.regex
口味,但欢迎其他口味。
Appendix
本节没有什么新内容;它只是用一个例子来说明上面提到的问题。
让我们将上面的示例带到下一步:我们现在要匹配这些:
<amy=amy>
(bob=bob)
[carol=carol]
但不是这些:
<amy=amy) # non-matching bracket
<amy=bob> # left hand side not equal to right hand side
使用替代技术,我们可以得到以下有效的方法(如 rubular.com 上所示 http://www.rubular.com/r/ojoknCda2A):
<((\w+)=\2)>|\(((\w+)=\4)\)|\[((\w+)=\6)\]
如上所述:
- 主要模式不能简单地重复;反向引用必须重新编号
- 如果发生变化,重复也意味着维护噩梦
- 根据备用匹配项,我们必须查询
\1 \2
, \3 \4
, or \5 \6
在进行真正的匹配之前,您可以使用前瞻来“锁定”组编号。
String s = "<amy=amy>(bob=bob)[carol=carol]";
Pattern p = Pattern.compile(
"(?=[<(\\[]((\\w+)=\\2))(?:<\\1>|\\(\\1\\)|\\[\\1\\])");
Matcher m = p.matcher(s);
while(m.find())
{
System.out.printf("found %s in %s%n", m.group(2), m.group());
}
output:
found amy in <amy=amy>
found bob in (bob=bob)
found carol in [carol=carol]
它仍然很难看,但是您不必每次进行更改时都重新计算所有组编号。例如,要添加对大括号的支持,只需:
"(?=[<(\\[{]((\\w+)=\\2))(?:<\\1>|\\(\\1\\)|\\[\\1\\]|\\{\\1\\})"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)