JavaのStringクラスの文字列置換

はまっていた人を久々に見かけたので。

JavaのStringクラスには文字列置換を行ってくれるメソッドが4種類用意されています。

  • replace(char oldChar, char newChar)
    この文字列内にあるすべてのoldCharをnewCharに置換した結果生成される文字列を返します。
  • replace(CharSequence target, CharSequence replacement)
    リテラル・ターゲット・シーケンスに一致するこの文字列の部分文字列を、指定されたリテラル置換シーケンスに置き換えます。
  • replaceAll(String regex, String replacement)
    指定された正規表現に一致する、この文字列の各部分文字列に対し、指定された置換を実行します。
  • replaceFirst(String regex, String replacement)
    指定された正規表現に一致する、この文字列の最初の部分文字列に対し、指定された置換を実行します。

歴史的経緯からいくつか注意点があるので、以下のとおり気をつけてください。

replace、replaceAllはすべてを置換する

replaceAllというメソッドがあるため、replaceは最初の一つしか置換してくれないんじゃないの?みたいな勘違いをしている人がたまにいますが、見つかったものが全て置換されます。最初の一つしか置換しないものはreplaceFirstのみです。

replaceAll、replaceFirstは正規表現を使用する

replaceAll、replaceFirstは引数として正規表現を使用します。正規表現はただの文字列ではなく、色々な文字集合を簡単に使いやすくしたものです。正規表現について詳しくはPatternクラスのJavaDocを参照してください。*1
正規表現を使用するため、一部の文字でエスケープが必要になります。そのため、ただの文字列リテラルを置換しようとした場合に意図したとおりに置換できないことがあります。注意が必要です。
また、Java1.3まではreplaceAllメソッドが正規表現ではなく、通常の文字列を受け付けるようになっていました。古くからJavaをやっている人の一部がまれに勘違いをしていることが未だにあるようですのでそこらへんについても注意が必要です。

追記:Java1.3の頃はreplaceメソッドでした。Java1.4で一度文字列を引数とするreplaceメソッドが消えて、Java5.0で復活したのが正しい経緯でした。 @skrbさんありがとうございます。

正規表現を使用する場合の性能は悪い

正規表現のマッチング自体の性能は優秀なのですが、正規表現コンパイル(解釈)にはそれなりの時間がかかります。
replaceAllを多用すると、それだけで性能劣化の原因になる場合もあります。
置換元として使用する文字列が不変であるならば、Java正規表現を表現しているPatternクラスを使いまわすことで性能向上する可能性があります。*2
詳細はString#replaceAllのJavaDocや、PatternクラスのJavaDocを参照してください。

これらのメソッドは文字列自体を変更しないので戻り値を使用する必要がある

JavaのStringはイミュータブル(不変)になっています。文字列自体は変更されません。

まとめ

ということで、色々注意点でした。いつの間にかメソッドの引数、戻り値の意味が変わっている場合もあるし、メソッドの使用方法についてきちんと確認するのは良い習慣なので、わかっていると思ってもJavaDocよみましょう。

*1:もちろん正規表現google検索をしても山のように出てきます。

*2:Patternクラスはスレッドセーフのため安全に使いまわすことができます