Java的replaceAll()方法中的正则表达式元字符“*”和“*?”行为奇怪

2022-09-02 21:01:49

可能的重复:
String.replaceAll() 异常与正则表达式中的贪婪量词 异常 正则表达式
中的奇怪行为

"a".replaceAll("a", "b")
"a".replaceAll("a+", "b")
"a".replaceAll("a+?", "b")

都回来了,为什么b

"a".replaceAll("a*", "b")

返回和bb

"a".replaceAll("a*?", "b")

返回?bab


答案 1
"a".replaceAll("a*", "b")

首先替换为 ,然后将指针前进到 .然后,它与字符串的末尾匹配,并替换为 。由于它与空字符串匹配,因此它会前进指针,从字符串中掉出并完成,从而得到 .abbbbb

"a".replaceAll("a*?", "b")

first 匹配字符串的开头并替换为 。它与 因为 in 表示“不贪婪”(尽可能少地匹配)不匹配。由于它与空字符串匹配,因此它会前进指针,跳过 。然后,它与字符串的末尾匹配,替换为字符串并退出字符串,从而得到 .最终结果与您所做的相同。ba?a*?abbab"a".replaceAll("", "b")


答案 2

发生这种情况是因为零宽度匹配。


"a".replaceAll("a*", "b")

将匹配两次:

  1. 尝试在字符串的开头匹配,贪婪消耗作为匹配。*a
  2. 前进到字符串中的下一个位置(现在在字符串末尾),尝试匹配,空字符串匹配。

    " a "
     \| \___ 2. match empty string
      \_____ 1. match "a"
    


"a".replaceAll("a*?", "b")

还将匹配两次:

  1. 尝试在字符串的开头进行匹配,不贪婪地匹配空字符串而不消耗 .*?a
  2. 前进到字符串中的下一个位置(现在在字符串的末尾),尝试匹配那里,空字符串匹配。

    " a "
     \  \___ 2. match empty string
      \_____ 1. match empty string