[英]Java regular expression boundary match?
我在一个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中明确地解决这个问题。 我最好的猜测是边界特征,但如果有人能提供解释,我将不胜感激
您看到此行为的原因是您的模式允许空匹配。 换句话说,如果你传递一个空字符串,你会在零位置看到一个匹配:
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的时间,即最后一个字符的时间:这里,“尾部”由空字符串组成。 这类似于调用"wow its cool".substring(12)
:在这种情况下你也会得到一个空字符串。
引擎将空字符串视为有效输入,并尝试将其与表达式匹配,如上例所示。 这会产生匹配,您的程序会正确报告。
[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
不匹配。 数= 9
最后它匹配最后一个字符旁边的空字符串。 所以现在计数是9+1=10
最后我们都知道m.start()
打印相应匹配的起始索引。
正则表达式简单地将模式与输入匹配,从给定的偏移量开始。 对于最后一场比赛,12的偏移量是在'酷'的最后一个字符之后的位置 - 你可能认为这是字符串的结尾,因此不能用于匹配目的 - 但你错了。 对于模式匹配,这是一个非常有效的起点。
正如您所述,您的正则表达式包含零字符的可能性,实际上,这是在最后一个字符结束之后但在字符串结束标记之前发生的事情(通常在正则表达式中由$表示)。
换句话说,没有测试超过最后一个字符的结尾,这意味着不会发生与字符串结尾相关的匹配 - 但是有许多正则表达式构造匹配字符串的结尾(并且你已经在这里显示其中一个)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.