我去年在看这个问题:Java Regex中的零长度匹配:
Pattern pattern = Pattern.compile("a?");
Matcher matcher = pattern.matcher("ababa");
while(matcher.find()){
System.out.println(matcher.start()+"["+matcher.group()+"]"+matcher.end());
}
产生输出:
0[a]1
1[]1
2[a]3
3[]3
4[a]5
5[]5
我想知道这是否正确。该模式匹配" a"或空字符串。当Matcher指向第一个" b"时,就没有" a",因此find()匹配空字符串。
但是,javadoc说:
This method starts at the beginning of this matcher's region, or, if a
previous invocation of the method was successful and the matcher has
not since been reset, at the first character not matched by the
previous match.
因此,当Matcher指向'b'时,不会匹配任何字符,并且find()会匹配一个空字符串,这意味着在此之后,与上一个匹配项不匹配的第一个字符(即空字符串)仍为'b '。根据以上所述,这应该意味着下一个find()应该在同一位置开始,这意味着代码应该无限循环。但这当然不是正在发生的事情。看起来当匹配空字符串时,它只是将起始点提高了1。
那么这是什么一回事?实现是错误的,还是javadoc遗漏了一些东西,还是我遗漏了一些东西?
不," b"与" a?"不匹配。 从输出1 [] 1可以看出,开始和结束是相同的,因此它是空匹配。 但是,在那种情况下,find()已消耗了" b"。 ajb提出的问题是为什么在这种情况下find()会不断向前发展。 答案是匹配的组与匹配的区域不同(也尝试打印matcher.regionEnd())。
它仍然没有道理。 在与第一个" a"匹配之后,其指向b。 然后,第二个find()返回空字符串,并且根据JLS,匹配器仍应指向下一个find()的b,因为第二个find()不匹配b。 因此,在我看来,匹配器在第二个find()之前应与第三个find()之前处于相同状态……但由于返回的结果不同,所以匹配有所不同。 regionStart()和regionEnd()都不会更改(我认为它们仅由region()更改)。 那有什么不同呢?
好的,当find()返回一个空字符串时,确实有一种特殊情况。为了明确起见,由于我认为有些人不理解该问题,因此我的问题是,为什么匹配器状态在第二个find()之前和第三个find()之前应该不同,因为"第一个字符与上一个字符不匹配"匹配"在两种情况下都相同。
区别在于,上一个匹配项的边界存储在匹配器的状态中,并且确实会影响下一个find(),但仅在这种情况下。从Matcher.java中的find()代码中:
int nextSearchIndex = last;
if (nextSearchIndex == first)
nextSearchIndex++;
除非最后一个find()返回一个空字符串(或者其他方法设置了first或last),否则last是开始搜索的地方,然后将其向上移动一个。这个代码段没有评论,所以我不确定目的是什么,但是看起来它是故意作空字符串匹配的特殊情况。不过,它似乎确实与javadoc矛盾,因为在这种情况下,搜索从javadoc声明的位置之外的其他地方开始。
编辑:顺便说一句,这的确有可能令人惊讶的结果:
Pattern p = Pattern.compile("a?");
Matcher m = p.matcher ("abcde");
m.find();
System.out.println("[" + m.group() +"]");
m.find();
System.out.println("[" + m.group() +"]");
m.usePattern (Pattern.compile("[bd]"));
m.find();
System.out.println("[" + m.group() +"]");
输出
[a]
[]
[d]
最后一个匹配项找不到" b",即使" b"字符??没有被任何先前的匹配项匹配,也不应该被跳过。不过,它有点晦涩。
a?表示零个或一个'a'字符,因此它将与a或" nothing"匹配-与位于" a"和" b"字符??之间的" a"字符和"虚无"匹配。
这是完全正确和预期的。
这是正确的,但缺少一个重要的额外细节。 默认情况下,正则表达式配置为贪婪,这意味着它将扩展以匹配最大可能的模式。 因此,即使0[]0应该在匹配列表中,也不会得到报告,因为0[a]1是在相同索引处的较大匹配。