繁体   English   中英

重访:Java正则表达式中的零长度匹配

[英]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()返回空字符串(或者firstlast由其他方法设置),然后向上移动一个。 这个代码段没有评论,所以我不确定目的是什么,但是看起来它是故意作空字符串匹配的特殊情况。 不过,它似乎确实与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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM