String.replaceAll(regex)进行两次相同的替换

时间:2011-12-22 13:07:02

标签: java regex

任何人都可以告诉我为什么

System.out.println("test".replaceAll(".*", "a"));

结果

aa

请注意,以下结果相同:

System.out.println("test".replaceAll(".*$", "a"));

我在java 6& 7并且两者似乎都表现得一样。 我错过了什么或者这是java正则表达式引擎中的错误吗?

1 个答案:

答案 0 :(得分:59)

这不是异常现象:.*可以匹配任何内容。

您要求替换所有出现次数:

  • 第一次匹配整个字符串,因此正则表达式引擎从下一个匹配的输入结束开始;
  • .*也匹配空字符串!因此,它匹配输入末尾的空字符串,并将其替换为a

使用.+代替不会出现此问题,因为此正则表达式无法匹配空字符串(它需要至少匹配一个字符)。

或者,使用.replaceFirst()仅替换第一次出现:

"test".replaceFirst(".*", "a")
       ^^^^^^^^^^^^

现在,为什么.*表现得像以及不匹配超过两次(理论上可以),这是一个值得考虑的有趣事情。见下文:

# Before first run
regex: |.*
input: |whatever
# After first run
regex: .*|
input: whatever|
#before second run
regex: |.*
input: whatever|
#after second run: since .* can match an empty string, it it satisfied...
regex: .*|
input: whatever|
# However, this means the regex engine matched an empty input.
# All regex engines, in this situation, will shift
# one character further in the input.
# So, before third run, the situation is:
regex: |.*
input: whatever<|ExhaustionOfInput>
# Nothing can ever match here: out

请注意,@ A.H。注释中的注释,并非所有正则表达式引擎都以这种方式运行。例如,GNU sed会认为在第一次匹配后它已经耗尽了输入。