我从去年开始看这个问题:Zero-length matches in 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”或空字符串。当匹配器指向第一个“b”时,没有“a”,因此find()匹配空字符串。
然而,javadoc说:
此方法从此匹配器区域的开头开始,或者,如果是 以前的方法调用是成功的,匹配器有 从没有重置,在第一个字符不匹配 上一场比赛。
因此,当匹配器指向'b'时,没有匹配的字符,find()匹配空字符串,这意味着在此之后,第一个与前一个匹配不匹配的字符(即空字符串)仍将是'b'。根据上面的说法,这应该意味着下一个find()应该从同一个地方开始,这意味着代码应该无限循环。但当然,这不是正在发生的事情。当一个空字符串匹配时,它看起来只是将起点加1。
那是怎么回事?实现是错误的,还是javadoc遗漏了什么,或者我错过了什么?
答案 0 :(得分:1)
a?
表示零或一个'a'字符,因此它会匹配a
或“无” - 它匹配“a”字符和“虚无” “将定位在”a“和”b“字符之间。
这是完全正确和预期的。
答案 1 :(得分:1)
好的,当find()返回一个空字符串时,看起来确实有一种特殊情况。为了说清楚,因为我认为有些人不理解这个问题,我的问题是为什么匹配器状态在第二个find()之前和第三个find()之前应该是不同的,因为“第一个字符与前一个不匹配匹配“在两种情况下都是相同的。
不同之处在于前一个匹配的边界存储在匹配器的状态中,而它们做会影响下一个find(),但仅限于这一情况。来自Matcher.java中的find()代码:
int nextSearchIndex = last;
if (nextSearchIndex == first)
nextSearchIndex++;
last
是搜索将要开始的地方,除非最后一个find()返回一个空字符串(或first
或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”字符未与之前的任何一场比赛相匹配,也不应该被跳过。不过,这有点模糊不清。