2012-02-10 55 views
4

有一个关于正则表达式的问题,并试图回答我发现了另一个奇怪的事情。在正则表达式中的奇怪行为

String x = "X"; 
System.out.println(x.replaceAll("X*", "Y")); 

这打印YY。为什么??

String x = "X"; 
System.out.println(x.replaceAll("X*?", "Y")); 

而这种打印YXY

为什么不愿意正则表达式不匹配 'X' 字?有"noting"X"nothing",但为什么先不匹配三个符号,匹配两个,然后一个而不是三个?和第二次正则表达式匹配只有"nothing" s而不是X

+0

在Perl/PCRE中用'X *?'代替将导致'YYY'。 – Qtax 2012-02-10 13:54:56

回答

8

让我们看看它们依次是:

"X".replaceAll("X*", "Y") 

有两场比赛:

  1. 在字符位置0,X匹配,并且被替换为Y
  2. 在字符位置1处,匹配空字符串,并将Y添加到输出中。

最终结果:YY

"X".replaceAll("X*?", "Y") 

还有两个匹配:

  1. 在字符位置0,空字符串匹配时,并Y被添加到输出。 此位置上的字符X未被匹配消耗,因此会逐字复制到输出中。
  2. 在字符位置1处,匹配空字符串,并将Y添加到输出中。

最终结果:YXY

+0

在第一种情况下,在第二步中(2.在字符位置1 ...)但没有位置1,它超出了字符串的边界,不是吗?在第一步之后,一切都应该结束,因为字符串结束 – shift66 2012-02-10 13:38:43

+0

@Ademiban:不完全。有一个位置'1'。考虑下面的正则表达式:'“$”'。根据定义,它可以匹配的* only *位置在字符串的最后一个字符之后。在这个例子中,这将位于'1'位置。正则表达式可以产生零长度匹配。 – NPE 2012-02-10 13:39:56

+0

很好的回答!让我添加一个可能有趣的笔记;)在第二种情况下,X自从*以来不匹配?意味着懒惰的匹配,即*之前的元素?如果仍然产生有效结果,则最好不匹配。 – 2012-02-10 13:44:50

1

*是一个棘手的'量词',因为它意味着'0或更多'。因此,它也匹配'0次X'(即空字符串)。

我会用

"X".replaceAll("X+", "Y") 

其中有预期的行为。

0

在您的第一个示例中,您使用的是“贪婪”量词。这意味着在尝试第一次匹配之前,输入字符串被强制完全读取,所以第一次尝试的是整个输入。如果输入匹配,匹配器会越过输入字符串,并在字符串末尾执行零长度匹配,因此您会看到两个匹配项。在第一次匹配尝试成功之前,贪婪的匹配器永远不会退回到字符X之前的零长度匹配。

在第二个示例中,您使用的是与“贪婪”相反的“不情愿”量词。它从一开始就开始,并尝试在未来的时间匹配一个字符(如果必须的话)。因此匹配“X”字符之前的零长匹配,匹配器向前移动1(这就是为什么您仍然可以在输出中看到“X”字符),其中下一个匹配现在是“X ”。
这里有一个很好的教程:http://docs.oracle.com/javase/tutorial/essential/regex/quant.html