给定正则表达式\w*(\s+|$)
和输入"foo"
我希望Java Matcher.find()
只有一次为真:\ w *会消耗foo,{{1} in(\ s + | $ )应该使用字符串的结尾。
我无法理解为什么第二个find()对于emtpy匹配也是如此。
示例代码:
$
预期(由我)输出:
public static void main(String[] args) {
Pattern p = Pattern.compile("\\w*(\\s+|$)");
Matcher m = p.matcher("foo");
while (m.find()) {
System.out.println("'" + m.group() + "'");
}
}
实际输出:
'foo'
更新
我的正则表达式示例应该只是\ w * $,以简化产生完全相同行为的讨论。
所以事情似乎是如何处理零长度匹配。
我发现方法'foo'
''
告诉您最后一次匹配到达输入的结尾,这样您就知道您不需要另一个Matcher.hitEnd()
Matcher.find()
while (!m.hitEnd() && m.find()) {
System.out.println("'" + m.group() + "'");
}
需要在!m.hitEnd()
之前,以免错过最后一个字。
答案 0 :(得分:4)
表达式\\w*
匹配零个或多个字符,因为您使用的是Kleene operator。
一种快速解决方法是将表达式更改为\\w+
修改强>:
在阅读Matcher的文档后,find方法“从此匹配器区域的开头开始,或者,如果先前调用该方法成功并且匹配器尚未重置,则在第一个字符与上一场比赛不匹配。“在这种情况下,在第一次调用时,所有字符都匹配,因此第二次调用从空开始。
答案 1 :(得分:1)
你的正则表达式可以导致零长度匹配,因为\w*
可以是零长度,$
总是零长度。
有关零长度匹配的完整说明,请参阅" Zero-Length Regex Matches"在http://www.regular-expressions.info。
最相关的部分在名为"在零长度正则表达式匹配后前进"
的部分中如果正则表达式可以在字符串中的任何位置找到零长度匹配,则。正则表达式
\d*
匹配零个或多个数字。如果主题字符串不包含任何数字,则此正则表达式在字符串中的每个位置找到零长度匹配。它在字符串abc
中找到4个匹配项,在三个字母的每个字母前面找到一个匹配项,在字符串末尾找到一个匹配项。
由于你的正则表达式首先与foo
匹配,所以它留在最后o
之后的位置,即在输入结束时,所以它完成了那轮搜索,但是并不意味着它是通过整体搜索来完成的。
它只是结束第一次匹配迭代的匹配,并将搜索位置留在输入的末尾。
在下一次迭代中,它可以进行零长度匹配,所以它将。当然,在零长度匹配之后,必须前进,否则它将永远停留在那里,并且从输入的最后位置前进会停止整体搜索,这就是为什么那里没有第三次迭代。
要修复正则表达式,所以它没有这样做,你可以使用匹配的正则表达式\w*\s+|\w+$
:
因为|
的任何一部分都不是空匹配,所以你所经历的不可能发生。但是,使用\w*
意味着您仍然可以找到没有任何字词的匹配项,例如
He said: "It's done"
使用该输入,正则表达式将匹配:
"He "
" " the space after the :
"s " match after the '
除非您真正想要的,否则您应该更改正则表达式以使用+
代替*
,即\w+(\s+|$)
答案 2 :(得分:1)
共有2个匹配项,一个用于foo
,另一个用于foo here->
。
如果匹配位置发生变化且具有
没有匹配的选项,它将匹配一个额外的时间。
每个比赛位置只发生一次 这是为了避免无限循环的无限 un-wisedom 。
并且,除了提供之外,它与EOS锚无关 没有匹配的选项。
您使用\w*
与foo
相同,即2次匹配。