可能重复:
String.replaceAll() anomaly with greedy quantifiers in regex
我正在编写使用Matcher#replaceAll
的代码,并发现以下结果非常令人困惑:
Pattern.compile("(.*)").matcher("sample").replaceAll("$1abc");
现在,我希望输出为sampleabc
,但Java会向我sampleabcabc
投掷。
有人有什么想法吗?
现在,当然,当我锚定模式(^(.*)$
)时,问题就会消失。我仍然不知道为什么地狱replaceAll
会做那样的双重替换。
并且在下面的代码中添加了对伤害的侮辱:
Pattern.compile("(.*)").matcher("sample").replaceFirst("$1abc")
按预期工作,仅返回sampleabc
。
答案 0 :(得分:5)
由于某种原因,它似乎与输入末尾的空字符串匹配。 (我可以看出为什么它会匹配;我很感兴趣它与匹配并且只匹配一次。)
如果您将replaceAll("$1abc")
更改为replaceAll("'$1'abc")
,则结果为'sample'abc''abc
。
请注意,如果您将(.*)
更改为(.+)
,那么它可以正常工作,因为它必须至少匹配一个字符。
此代码确认诊断:
Matcher matcher = Pattern.compile("(.*)").matcher("sample");
while (matcher.find()) {
System.out.printf("%d to %d\r\n",
matcher.start(),
matcher.end());
}
......输出:
0 to 6
6 to 6
答案 1 :(得分:5)
这里有两件事可以解释为什么会发生这种情况:
(.*)
将成功匹配空字符串。因此,在匹配整个字符串"sample"
之后,在e
之后尝试另一个匹配。即使没有剩下任何字符,匹配也会成功,并且会发生第二次替换。
不会发生其他替换,因为正则表达式引擎将始终向前移动。在最后一个字符是有效的起始索引之后,空字符串将匹配一次,但在匹配空字符串后,正则表达式引擎没有更多有效的起始位置来尝试匹配。
作为向正则表达式添加字符串锚点的替代方法的替代方法,您可以修改正则表达式,以便通过将(.*)
更改为(.+)
来匹配一个或多个字符。