正则表达式中的奇怪行为

时间:2012-02-10 13:27:36

标签: java regex regex-greedy

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

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"而不是X

3 个答案:

答案 0 :(得分:8)

让我们依次考虑它们:

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

有两场比赛:

  1. 在字符位置0,X匹配,并替换为Y
  2. 在字符位置1处,匹配空字符串,并将Y添加到输出中。
  3. 最终结果:YY

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

    还有两场比赛:

    1. 在字符位置0处,匹配空字符串,并将Y添加到输出中。 此位置的字符X未被匹配使用,因此会逐字复制到输出中。
    2. 在字符位置1处,匹配空字符串,并将Y添加到输出中。
    3. 最终结果:YXY

答案 1 :(得分:1)

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

我会用

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

具有预期的行为。

答案 2 :(得分:0)

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

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