为什么正则表达式\ w *(\ s + | $)找到“foo”(Java)的2个匹配项?

时间:2017-07-13 22:53:00

标签: java regex

给定正则表达式\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()之前,以免错过最后一个字。

3 个答案:

答案 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次匹配。