Javaについて徹底解説!

JavaのString.replaceAllと正規表現で、スマートに文字列置換!

String.replaceAllは、文字列中を正規表現でマッチングし、マッチした部分を置換するものです。同じような動きをするものとして、replaceFirstがあります。

この記事では、replaceAll/replaceFirstの使い方と、プログラミングの現場でよく見かける応用例を初心者向けにお伝えします。

なお、似たメソッドとしてString.replaceがあります。こちらは正規表現ではなく固定された文字列を対象に置換します。こちらも初心者向けの記事がありますので、よろしければご覧ください。

※この記事のサンプルは、Java 10の環境で動作確認しています。

1.String.replaceAllは正規表現のマッチ箇所を置換する

String.replaceAllは、「正規表現」がマッチした箇所全てを、指定の文字列に置換した文字列を戻すメソッドです。それ以外の機能はString.replaceと同じです。

正規表現(Regular Expression)とは、文字や数字の「パターン」を指定するものです。replaceAllが真価を発揮するのは、置換したい文字列に何かしらの明確なパターンがある時です。

1-1.例:英語小文字・数字とのマッチング

例えば、正規表現の[a-z]は英語の小文字(aからzの全て)にマッチしますし、[0-9]は数字(09の全て)にマッチします。実際には以下のようにして用います。

ちなみに、同じようなことをString.replaceで行うには、例えば以下のようにしなければなりません。行数は増えますし、メソッドを呼び出す回数が多いので性能も悪そうです。そう見ると、正規表現は効率が良いですね。

もちろん、正規表現へは日本語も使えます。(いわゆる)全角半角もJavaの内部ではきちんと別物なので注意しましょう。

1-2.Javaで使える正規表現のパターン例

正規表現では以下のものを覚えておけば最初の内は大体OKです。もっと凝ったことをやりたければ、そこからどんどん応用していけばいいのです。

[] ← []の中に指定した文字との一致

[a-z] ← 英語小文字

[A-Z] ← 英語大文字

[0-9] ← 数字

() ← 文字列のグループ化

| ← グループ化した文字列内での選択

+ ← 文字あるいは文字列が1回以上繰り返し出現する

* ← 文字あるいは文字列が0回以上繰り返し出現する

^ ← 文字列の先頭

$ ← 文字列の末尾

なお、Javaで使える正規表現のパターンの詳細は、例えばJavadocjava.util.regex.Patternをご覧ください。記載されている分量は多いですが、実務で頻繁に使うのはその中の一部です。

1-3.特殊文字の無効化には\Pattern.quoteを使う

正規表現では、前述のとおり[]()\|などいくつかの文字を特別な意味に用います。これらの文字をそのまま正規表現中で指定したい場合は、\により無効化しなければなりません(一般にはエスケープと呼ばれます)

以下の例では、正規表現では文字を選択指定する [] 自体を置換したいのですが、そのままでは正規表現の文法エラーになってしまいます。

これを動くようにするには、以下のようにして特別な意味を持つ文字をエスケープします。\\を二つ書くのは、最終的に\[\]という文字列にしたいからです。Java “” の中では、\自体が特別な意味を持つからですね。

ただし、いちいち手でエスケープするのも大変なので、まとめて全部エスケープしたいならPattern.quoteが使えます。実行結果に付く\Q\Eは、範囲内の全ての特殊文字をエスケープするものです。正確に行うには色々考慮する必要がありますが、それを全部やってくれます。

2.String.replaceFirstは最初のマッチ箇所だけを置換する

String.replaceFirstは、replaceAllの限定版で、正規表現にマッチした最初の一箇所目だけを置換します。

ですので、以下の例では最初に出現した英語小文字(Theh)のみが置換されました。

3.【応用】String.replaceAllの応用例

String.replaceAll/replaceFirstの強みは、置換対象の文字列を正規表現で指定できることです。この指定をどう工夫するかで、色々な応用ができるのです。以下はその一例です。

3-1.空白の削除や詰め

以下のように空白削除にも使えます。簡単かつ地味ですが、利用頻度は結構高いですよ。置換先の文字列を空文字列(長さ0の文字列、“”)とすれば、削除と同じ意味になるのです。

空白扱いしたい文字は正規表現で自由に指定できますので、例えば以下のようにもできます。

パターンを少し変えるだけで、複数の空白を1つにまとめるのも簡単にできます。いくつ空白があってもパターンにマッチすればいい、ということが大きな強みです。

3-2.全角・半角空白両対応trim

標準のString.trimは空白(※)だけ削除してくれますが、私たち日本人だと(いわゆる)全角空白もtrimしたいですよね。その場合も、replaceFirstを使えば楽々です。正確には空白よりコードポイントが小さい文字

要は、先頭(^)の後と末尾($)の前で空白扱いしたいものがあれば、それを“”に置換しているだけです。replaceAllでも結果は同じですが、1回だけになるのでこちらの方が意味が明確になるでしょう。

trimする範囲を先頭だけ、末尾だけとしたいなら、どちらか片方のreplaceFirstだけを実行すればOKです。

3-3.特定文言のマスク・文言の修正

何かの文章の中に含まれる特定キーワードをマスクしたい場合があります。replaceでも良いですが、数が多い場合だと一つのパターンで全部賄ってしまった方が楽な場合もあります。キーワードを|で繋いでいくだけです。

ちなみに、大文字・小文字を無視したいなら以下のようにもできます。(?i)は大文字・小文字の区別をなくすためのオプションです。この他にも全角半角を同一視するものなど色々なオプションがありますので、興味があれば「java 正規表現 オプション」などのキーワードで調べてみてもいいでしょう。

これはちょっとした文言の修正にも使えます。この例は音引きの修正で、文中の「コンピュータ」あるいは「コンピューター」をどちらかに統一するものです。ここから工夫をすれば、送り仮名の統一にも使えますね。

3-4.改行コードや区切り文字の統一

1つの文字列やファイルの中に改行コードが混在していることがあります。Windows系なら\r\nUNIX系なら\n、古いMacなら\rです。それを統一するのも簡単です。正規表現の中では、\を指定したい場合は\\を二つ重ねる必要があることに注意しましょう。

複数ある区切り文字を一つにするのも同じように一発です。ログなどを分析しやすくするため、タブなどにひとまとめにするのに使えますね。

3-5.HTML/XML中の属性値の削除

HTML中で特定の条件を満たす属性値(attribute)をごっそり削除できたりします。削除したい条件が、正規表現で上手く表現できるかがポイントです。ここでは、属性名がheightかつ属性値が数値のものを選んでいます。

4.【中級者向け】String.replaceAllのもう少し進んだ話題

4-1.マッチした文字列の参照($0$1$2…)

String.replaceAllの2番目の引数の中では、正規表現中で「()」で囲んだ部分を「$ + 数値」という形式で参照できます。例えば、以下のようにします。

ここで、$0はマッチした部分全体で、上記の例ではそれぞれの数字部分です。これは順番に$1$2$3…と続けられ、正規表現内で()により囲まれた部分を順番に参照できます。以下では、マッチした部分の並び替えをしています。

これの使いどころは少し難しいです。ですが、先述した応用例でも一部この機能を使っているところがありますので、使いようによっては便利なものなのです。

4-2.PatternとMatcherで正規表現の世界に飛び込もう!

String.replaceAllは、実は正規表現のAPIであるjava.util.regex.Patternとjava.util.regex.Matcherを意識せずに使うためのものです。裏では以下のような処理が行われています。

正規表現で凝ったことをやりたい場合は、String.replaceAllだけでは限界がありますので、Matcherの力を借りる必要があります。

一例として、マッチした部分をすべて出力するには以下のようにします。String.replaceAll$0$1$2で参照できていたものです。

これはMatcherのほんの一機能です。もっといろいろな凄いことができますので、ぜひやってみましょう。作業効率化に繋がるものがあるかもしれません。

5.まとめ

String.replaceAllは、正規表現のパターンにマッチする部分を指定した文字列で置換するものです。replaceFirstは、最初にマッチした部分だけ置換するものです。

この記事では応用例をいくつかお伝えしましたが、それでも正規表現が持つ力をほんの少し垣間見ただけです。String.replaceAllは、正規表現を簡易的に扱うためのものでしかありません。Javaで正規表現に真の力を発揮させるためには、java.util.Patternjava.util.Matcherを深く知る必要があります。

String.replaceAllを足掛かりに、ぜひ正規表現の世界に足を踏み入れましょう。Javaに限らず、エディタなどでも正規表現を使えることがほとんどですので、上手く使いこなせればあなたの作業効率が一気に良くなりますよ!!

『技術力』と『人間力』を高め市場価値の高いエンジニアを目指しませんか?

私たちは「技術力」だけでなく「人間力」の向上をもって遙かに高い水準の成果を出し、関わる全ての人々に感動を与え続ける集団でありたいと考えています。

高い水準で仕事を進めていただくためにも、弊社では次のような環境を用意しています。

  • 定年までIT業界で働くためのスキル(技術力、人間力)が身につく支援
  • 「給与が上がらない」を解消する6ヶ月に1度の明確な人事評価制度
  • 平均残業時間17時間!毎週の稼動確認を徹底しているから実現できる働きやすい環境

現在、株式会社ボールドでは「キャリア採用」のエントリーを受付中です。

まずは以下のボタンより弊社の紹介をご覧いただき、あなたの望むキャリアビジョンをエントリーフォームより詳しくお聞かせください。