導入
Javaで文字列操作を行う際、正規表現は強力な武器となります。特に「特定のパターンに一致した部分文字列を抽出したい」という要件は、ログ解析や入力値のバリデーション、データ変換など、実務で頻繁に遭遇します。しかし、Matcherのメソッド群、特にgroup()の挙動を正しく理解していないと、意図しない例外や空の結果に悩まされることがあります。今回は、マッチした文字列全体を取得する基本から、実務で役立つ名前付きグループの活用法までを解説します。
基礎知識
Javaの正規表現は、主にjava.util.regexパッケージの「Pattern」クラスと「Matcher」クラスを使用して扱います。
・Pattern: 正規表現のコンパイル済み表現です。
・Matcher: Patternを特定の入力文字列に対して適用するためのエンジンです。
ここで重要なのが「グループ」という概念です。正規表現内で括弧 `()` を使用すると、その部分は「キャプチャグループ」として扱われます。
・matcher.group(0): マッチした文字列全体を指します。
・matcher.group(1以降): 括弧で囲まれた部分(サブグループ)を指します。
実務では、まず全体を取得してから必要に応じて部分抽出を行うのが定石です。
実装/解決策
マッチングを行うには、まずmatcher.find()メソッドを呼び出し、真偽値を確認する必要があります。これを忘れると、IllegalStateExceptionが発生し、プログラムがクラッシュします。
また、Java 7以降では「名前付きグループ」が利用可能です。正規表現内で `(?
サンプルプログラム
以下のコードは、ログファイルから「日付」と「エラーコード」を抽出する、実務でよくあるシナリオを想定したものです。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexSample {
public static void main(String[] args) {
// 日付(YYYY-MM-DD)とエラーコード(E-XXX)を抽出するパターン
// 名前付きグループ: ?
String regex = “(?\\d+)";
String logLine = "2023-10-27 ERROR: 500 Internal Server Error";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(logLine);
// find()でマッチするか確認(これを行わないとgroup()呼び出しでエラーになる)
if (matcher.find()) {
// マッチした全体を取得
System.out.println("全体: " + matcher.group(0));
// 名前付きグループで取得(インデックス指定より保守性が高い)
System.out.println("日付: " + matcher.group("date"));
System.out.println("コード: " + matcher.group("code"));
} else {
System.out.println("パターンに一致しませんでした。");
}
}
}
応用・注意点
実務で陥りやすい罠として、「マルチマッチング時のループ忘れ」があります。find()は一度呼ぶと次のマッチ位置へ進みます。全ての出現箇所を取得したい場合は、必ずwhile (matcher.find()) { ... } ループを使用してください。
また、正規表現のコンパイルコストについても留意が必要です。ループ内で毎回Pattern.compile()を呼び出すとパフォーマンスが低下します。定数として定義するか、staticフィールドで保持するようにしましょう。
最後に、マッチしなかった場合にgroup()を呼ぶと例外が発生するため、必ずif (matcher.find()) や while (matcher.find()) のブロック内で処理を行うことを徹底してください。

コメント