Java替换所有反向引用

时间:2013-01-24 23:04:34

标签: java regex replaceall

  

可能重复:
  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

2 个答案:

答案 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之后尝试另一个匹配。即使没有剩下任何字符,匹配也会成功,并且会发生第二次替换。

不会发生其他替换,因为正则表达式引擎将始终向前移动。在最后一个字符是有效的起始索引之后,空字符串将匹配一次,但在匹配空字符串后,正则表达式引擎没有更多有效的起始位置来尝试匹配。

作为向正则表达式添加字符串锚点的替代方法的替代方法,您可以修改正则表达式,以便通过将(.*)更改为(.+)来匹配一个或多个字符。