導入
文字列の置換を行う際、単純な`String.replaceAll`では対応できない複雑な処理が必要になることはありませんか?例えば「マッチした内容を加工してから置換したい」「マッチした値に基づいて計算を行いたい」といったケースです。このような課題を解決するのが、`Matcher.appendReplacement`メソッドです。このメソッドを使えば、置換処理を逐次的に制御でき、より高度な文字列操作が可能になります。
基礎知識
Javaの正規表現は`java.util.regex`パッケージの`Pattern`クラスと`Matcher`クラスを使用して扱います。
Patternは正規表現のパターンをコンパイルしたオブジェクトで、Matcherはそのパターンを文字列に適用するためのエンジンです。
通常、文字列を置換するには`replaceAll`を使いますが、これでは「マッチした箇所をすべて同じルールで置換」することしかできません。一方、`appendReplacement`は、マッチした部分を一つずつ処理しながら、結果を`StringBuilder`に構築していく手法をとるため、プログラマが細かなロジックを挟み込む余地が生まれます。
実装/解決策
`appendReplacement`を利用する際は、以下のステップを踏みます。
1. `Pattern`で正規表現を定義し、対象文字列に対して`Matcher`を作成する。
2. `while(matcher.find())`ループでマッチ箇所を走査する。
3. ループ内で`matcher.appendReplacement(sb, replacement)`を呼び出し、マッチ箇所を置換する。
4. 最後に`matcher.appendTail(sb)`を呼び出し、残りの文字列を結合して完了させる。
特に、名前付きグループ(Named groups)を利用すると、マッチした特定の部分を`matcher.group(“グループ名”)`で取得できるため、可読性と保守性が大幅に向上します。
サンプルプログラム
以下のコードは、文字列内の数値を見つけて、その値を2倍にして置換する例です。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExample {
public static void main(String[] args) {
String input = “商品A: 100円, 商品B: 200円”;
// 数値をキャプチャする正規表現(名前付きグループ ‘price’ を使用)
Pattern p = Pattern.compile(“(?
Matcher m = p.matcher(input);
StringBuilder sb = new StringBuilder();
// マッチ箇所を逐次処理
while (m.find()) {
// キャプチャした値を取得して計算
int price = Integer.parseInt(m.group(“price”));
String replacement = (price 2) + “円”;
// マッチした箇所を計算結果で置換し、StringBuilderに追加
// 第2引数にはバックスラッシュやドル記号が含まれる場合があるためquoteReplacementを使用
m.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
// 残りの文字列を末尾に追加
m.appendTail(sb);
System.out.println(“置換前: ” + input);
System.out.println(“置換後: ” + sb.toString());
}
}
応用・注意点
現場でこの手法を使う際に注意すべき点が2つあります。
1つ目は、Matcher.quoteReplacementの利用です。置換後の文字列に「$」や「\」が含まれていると、正規表現エンジンが特殊な意味として解釈してしまい、`IllegalArgumentException`が発生することがあります。動的に生成する置換文字列には必ずこのメソッドを通すようにしましょう。
2つ目は、ループ処理の書き漏らしです。`appendTail`を呼び忘れると、最後にマッチした箇所より後ろの文字列がすべて消えてしまいます。必ず`while`ループの外で呼び出すことを忘れないでください。これらを意識するだけで、Javaでの文字列操作の幅が格段に広がります。

コメント