Java 正则表达式中的奇怪行为

Java 正则表达式中的奇怪行为,java,regex,regex-greedy,Java,Regex,Regex Greedy,有一个关于regex的问题,试图回答,我发现了另一个奇怪的事情 String x = "X"; System.out.println(x.replaceAll("X*", "Y")); 这是YY。为什么 String x = "X"; System.out.println(x.replaceAll("X*?", "Y")); 这个印的是YXY 为什么不情愿的正则表达式不匹配“X”字符?有“注意到”X“什么都没有”,但为什么首先不匹配三个符号,然后匹配两个,然后匹配一个而不是三个?第二正则表达

有一个关于regex的问题,试图回答,我发现了另一个奇怪的事情

String x = "X";
System.out.println(x.replaceAll("X*", "Y"));
这是YY。为什么

String x = "X";
System.out.println(x.replaceAll("X*?", "Y"));
这个印的是YXY


为什么不情愿的正则表达式不匹配“X”字符?有
“注意到”X“什么都没有”
,但为什么首先不匹配三个符号,然后匹配两个,然后匹配一个而不是三个?第二正则表达式只匹配代码>“没有”>代码> s,而不是<代码> x>代码>

依次让我们考虑:

"X".replaceAll("X*", "Y")
有两个匹配项:

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

    "X".replaceAll("X*?", "Y")
    
    还有两个匹配项:

  • 在字符位置0处,匹配空字符串,并将
    Y
    添加到输出中此位置的字符
    X
    ,未被匹配使用,因此被逐字复制到输出中。
  • 在字符位置1,匹配空字符串,并将
    Y
    添加到输出中

  • 最终结果:
    YXY

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

    我会用

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

    它具有预期的行为。

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

    在第二个例子中,你使用了一个“不情愿”的量词,它与“贪婪”相反。它从开头开始,并在以后的时间尝试匹配一个字符(如果必须的话)。因此,匹配“X”字符之前的零长度匹配,匹配器向前移动1(这就是为什么您仍然在输出中看到“X”字符),其中下一个匹配现在是“X”之后的零长度匹配。

    这里有一个很好的教程:

    在第一种情况下,在第二步中(2.字符位置1…),但没有位置1,它超出了字符串的界限,不是吗?在第一步之后,一切都应该结束,因为字符串结束了。@Ademiban:不完全是。有一个位置
    1
    。考虑下面的正则表达式:<代码>“$”/代码>。根据定义,它唯一可以匹配的位置是字符串的最后一个字符之后。在本例中,它将位于位置
    1
    。同样的事情也发生在可以生成零长度匹配的正则表达式上。答案很好!不过,让我补充一条可能很有趣的注释;)在第二个场景中,X不匹配,因为*?表示延迟匹配,即*之前的元素?如果仍然产生有效结果,则最好不匹配。@aix,您的意思是在第1类位置上有一种行尾符号?@Ademiban:差不多。换句话说,完全可选的正则表达式可以在字符串的最后一个字符之后生成匹配项。在Perl/PCRE中替换为
    X*?
    将导致
    YYY