假设我们有以下输入:
<amy>
(bob)
<carol)
(dean>
我们还有以下正则表达式:
<(\w+)>|\((\w+)\)
现在我们得到两个匹配项 ( as seen on rubular.com ):
-
<amy>
是一场比赛,\1
捕获amy
,\2
失败 -
(bob)
是一场比赛,\2
捕获bob
,\1
失败
这个正则表达式完成了大部分我们想要的,它们是:
- 正确匹配左括号和右括号(即不混合)
- 它捕获了我们感兴趣的部分
但是,它也有一些缺点:
- 重复捕获模式(即“主要”部分)
- 只有
\w+
在这种情况下,但一般来说,这可能非常复杂,- 如果涉及反向引用,则必须为每个替代项重新编号!
- 重复使维护成为噩梦! (如果它改变了怎么办?)
- 只有
- 这些组基本上是重复的
- 根据备用匹配项,我们必须查询不同的组
- 只有
\1
或\2
在这种情况下,但通常“主要”部分可以有自己的捕获组!
- 只有
- 这不仅不方便,而且可能存在不可行的情况(例如,当我们使用仅限于查询一组的自定义正则表达式框架时)
- 根据备用匹配项,我们必须查询不同的组
- 如果我们还想匹配
{...}
,情况会迅速恶化,[...]
等
所以问题很明显:我们如何在不重复“主要”模式的情况下做到这一点?
Note: for the most part I'm interested in
java.util.regex
flavor, but other flavors are welcomed.
附录
本节没有新内容;仅举例说明上述问题。
让我们把上面的例子带到下一步:我们现在要匹配这些:
<amy=amy>
(bob=bob)
[carol=carol]
但不是这些:
<amy=amy) # non-matching bracket
<amy=bob> # left hand side not equal to right hand side
使用替代技术,我们可以使用以下方法 ( as seen on rubular.com ):
<((\w+)=\2)>|\(((\w+)=\4)\)|\[((\w+)=\6)\]
如上所述:
- 不能简单地重复主要模式;反向引用必须重新编号
- 如果发生变化,重复也意味着维护噩梦
- 根据备用匹配项,我们必须查询
\1 \2
,\3 \4
, 或\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());
}
输出:
found amy in <amy=amy>
found bob in (bob=bob)
found carol in [carol=carol]
它仍然非常丑陋,但您不必每次进行更改时都重新计算所有组号。例如,要添加对大括号的支持,只需:
"(?=[<(\\[{]((\\w+)=\\2))(?:<\\1>|\\(\\1\\)|\\[\\1\\]|\\{\\1\\})"
关于java - 使用同一组捕获 <thisPartOnly> 和 (thisPartOnly),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3165755/