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

nab*_*lex 41 java regex

谁能告诉我为什么

System.out.println("test".replaceAll(".*", "a"));
Run Code Online (Sandbox Code Playgroud)

结果是

aa
Run Code Online (Sandbox Code Playgroud)

请注意,以下结果相同:

System.out.println("test".replaceAll(".*$", "a"));
Run Code Online (Sandbox Code Playgroud)

我已经在java 6和7上测试了它,两者似乎都表现得一样.我错过了什么或者这是java正则表达式引擎中的错误吗?

fge*_*fge 60

这不是一个异常:.*可以匹配任何东西.

您要求替换所有出现的事件:

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

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

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

"test".replaceFirst(".*", "a")
       ^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

现在,为什么.*表现得像它一样并且不匹配超过两次(理论上可能)是一个有趣的事情要考虑.见下文:

# 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
Run Code Online (Sandbox Code Playgroud)

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

  • @ChrisDolan:`sed`仅产生'a`,但我怀疑它是一个bug.:-) (8认同)
  • 解决这个问题的另一种方法:使用`^.*` - 由于显而易见的原因,这只会匹配`a`一次. (8认同)
  • 感谢您的反馈,我一直在使用正则表达式,但从未遇到过这个问题.每天学些新东西... (2认同)