【问题标题】:Strange behavior in regexes正则表达式中的奇怪行为
【发布时间】:2012-03-02 23:10:04
【问题描述】:

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

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?

【问题讨论】:

  • 在 Perl/PCRE 中用X*? 替换将导致YYY

标签: java regex regex-greedy


【解决方案1】:

让我们依次考虑:

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

有两个匹配项:

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

最终结果:YY

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

还有两个匹配项:

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

最终结果:YXY

【讨论】:

  • 在第一种情况下,在第二步(2。在字符位置 1...)但没有位置 1,它超出了字符串的范围,不是吗?在第一步之后一切都应该结束了,因为字符串结束了。
  • @Ademiban:不完全是。有一个职位1。考虑以下正则表达式:"$"。根据定义,它可以匹配的 only 位置在字符串的最后一个字符之后。在此示例中,它位于位置 1。可以产生零长度匹配的正则表达式也会发生同样的事情。
  • 很好的答案!不过,让我添加一个可能有趣的注释;)在第二种情况下,X 不匹配,因为 *?意味着惰性匹配,即 *? 之前的元素?如果仍然产生有效结果,则最好不匹配。
  • @aix,你的意思是在位置 1 上有一种行尾符号?
  • @Ademiban:差不多。换句话说,一个完全可选的正则表达式可以在字符串的最后一个字符之后产生匹配。
【解决方案2】:

* 是一个棘手的“量词”,因为它表示“0 或更多”。因此,它也匹配“0 次 X”(即空字符串)。

我会用

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

具有预期行为。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2018-06-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-17
      • 1970-01-01
      • 2013-07-13
      • 1970-01-01
      相关资源
      最近更新 更多