Java正则表达式边界匹配?

时间:2014-12-27 13:49:11

标签: java regex string

我在一个Java测试套件中发现了以下问题

    Pattern p = Pattern.compile("[wow]*");
    Matcher m = p.matcher("wow its cool");
    boolean b = false;
    while (b = m.find()) {
        System.out.print(m.start() + " \"" + m.group() + "\" ");
    }

其中输出似乎如下

0 "wow" 3 "" 4 "" 5 "" 6 "" 7 "" 8 "" 9 "oo" 11 "" 12 ""

直到最后一场比赛很清楚,模式[哇] *贪婪地匹配0或更多' w'和' o'字符,而对于不匹配的字符,包括空格,它会导致空字符串。但是在匹配了最后一个' l'与11"",以下12""似乎不清楚。在测试解决方案中没有详细说明,我也无法从javadoc中明确地解决这个问题。我最好的猜测是边界特征,但如果有人能提供解释,我将不胜感激

3 个答案:

答案 0 :(得分:3)

您看到此行为的原因是您的模式允许空匹配。换句话说,如果你传递一个空字符串,你会在零位置看到一个匹配:

Pattern p = Pattern.compile("[wow]*"); // One of the two 'w's is redundant, but the engine is OK with it
Matcher m = p.matcher("");             // Passing an empty string results in a valid match that is empty
boolean b = false;
while (b = m.find()) {
    System.out.print(m.start() + " \"" + m.group() + "\" ");
}

这将打印0 "",因为空字符串与表达式的任何其他匹配项一样好。

回到你的例子,每当引擎发现一个匹配项(包括一个空的匹配项)时,它会通过一个字符前进。 "前进一个"意味着引擎会考虑尾部"在下一个位置的字符串。这包括正则表达式引擎处于位置11的时间,即最后一个字符的时间:这里," tail"由一个空字符串组成。这类似于调用"wow its cool".substring(12):在这种情况下你也会得到一个空字符串。

引擎将空字符串视为有效输入,并尝试将其与表达式匹配,如上例所示。这会产生匹配,程序会正确报告。

答案 1 :(得分:3)

  • [wow]*匹配第一个wow字符串。 count = 1

  • 由于字符类旁边有*零或更多),[wow]*这个正则表达式会匹配一个空字符串,该字符串存在于字符之前与上述模式不匹配。因此它匹配前面存在于第一个空间的边界或空白空间。数= 2。

  • its与上述正则表达式不匹配。所以它匹配每个字符之前存在的空字符串。因此,计数为2+3=5

  • 并且第二个空格与上述正则表达式不匹配。所以我们得到一个空字符串作为匹配。 5+1=6

  • c与上述正则表达式不匹配。因此它匹配之前存在的空格c 6+1=7

  • oo与上述正则表达式匹配。 [wow]*。所以它匹配oo,这被认为是1匹配。因此,我们将7+1=8作为计数。

  • l不匹配。 Count = 9

  • 最后它匹配最后一个字符旁边的空字符串。所以现在计数是9+1=10

  • 最后我们都知道m.start()会打印相应匹配的起始索引。

DEMO

答案 2 :(得分:0)

正则表达式只是将模式与输入匹配,从给定的偏移量开始。 对于最后一场比赛,12的偏移量是在' cool'的最后一个字符之后的点。 - 您可能认为这是字符串的结尾,因此不能用于匹配目的 - 但您错了。对于模式匹配,这是一个非常有效的起点。

正如您所说,您的正则表达式包含零字符的可能性,实际上,这是在最后一个字符结束之后但在字符串结束标记之前发生的事情(通常在正则表达式中由$表示)

换句话说,没有测试超过最后一个字符的结尾,这意味着不会发生与字符串结尾相关的匹配 - 但是有许多正则表达式结构与字符串的结尾相匹配(和你在这里展示了其中一个)。