7

重複の可能性:
String.replaceAll() 正規表現の貪欲な量指定子による異常

を使用するコードを書いていてMatcher#replaceAll、次の結果が非常に紛らわしいことがわかりました。

Pattern.compile("(.*)").matcher("sample").replaceAll("$1abc");

今、私は出力が期待しますsampleabcが、Javaは私に投げますsampleabcabc.

誰にも理由はありますか?

確かに、パターン ( ^(.*)$) を固定すると、問題はなくなります。replaceAllそれでも、なぜそんな二重交換をするのかわかりません。

そして、怪我に侮辱を加えるために、次のコード:

Pattern.compile("(.*)").matcher("sample").replaceFirst("$1abc")

期待どおりに動作し、ちょうど を返しますsampleabc

4

2 に答える 2

5

何らかの理由で、入力の最後にある空の文字列と一致しているようです。(なぜ一致するのかがわかります。1だけ一致することに興味があります。)

結果に変更replaceAll("$1abc")した場合はです。replaceAll("'$1'abc")'sample'abc''abc

(.*)に変更する(.+)と、少なくとも1つの文字と一致する必要があるため、正しく機能することに注意してください。

診断はこのコードによって確認されます:

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
于 2013-01-24T23:09:42.030 に答える
5

これが発生する理由を説明する2つのことがここで起こっています:

  • (.*)空の文字列と正常に一致します。
  • 試合が成功した後、前の試合の終了後1ポジションで別の試合が試みられます。

したがって、文字列全体"sample"が一致した後、の直後に別の一致が試行されeます。キャラクターが残っていなくても、試合は成功し、2回目の交代が発生します。

正規表現エンジンは常に前進するため、追加の置換は発生しません。最後の文字の直後は有効な開始インデックスであるため、空の文字列は1回一致しますが、空の文字列が一致すると、正規表現エンジンが一致を試行するための有効な開始位置はなくなります。

文字列アンカーの先頭を正規表現に追加する代わりに、に変更して1つ以上の文字と一致するように正規表現を変更でき(.*)ます(.+)

于 2013-01-24T23:10:23.193 に答える