[英]Revisited: zero-length matches in Java regex
我去年在看这个问题: 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说:
此方法从此匹配器区域的开始处开始,或者,如果该方法的先前调用成功并且自此之后未重置匹配器,则从与先前匹配项不匹配的第一个字符开始。
因此,当Matcher指向'b'时,不会匹配任何字符,并且find()会匹配一个空字符串,这意味着在此之后,与上一个匹配项不匹配的第一个字符(即空字符串)仍为'b ”。 根据以上所述,这应该意味着下一个find()应该在同一位置开始,这意味着代码应该无限循环。 但这当然不是正在发生的事情。 看起来当匹配空字符串时,它只是将起始点提高了1。
那么这是什么一回事? 实现是错误的,还是javadoc遗漏了一些东西,还是我遗漏了一些东西?
a?
表示零个或一个'a'字符 ,因此它将匹配a
或“ nothing”-它匹配位于“ a”和“ b”字符之间的“ a”字符和“ nothingness”。
这是完全正确和预期的。
好的,当find()返回一个空字符串时,确实有一种特殊情况。 为了明确起见,由于我认为有些人不理解该问题,因此我的问题是,为什么匹配器状态在第二个find()和第三个find()之前应该有所不同,因为“第一个字符与上一个字符不匹配”匹配”在两种情况下都相同。
区别在于,上一个匹配项的边界存储在匹配器的状态中,并且确实会影响下一个find(),但仅在这种情况下。 从Matcher.java中的find()代码中:
int nextSearchIndex = last;
if (nextSearchIndex == first)
nextSearchIndex++;
last
是开始搜索的地方,除非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”字符没有被任何先前的匹配项匹配,也不应该被跳过。 不过,它有点晦涩。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.