こんにちは、かつコーチです。
メールアドレスの形式チェックや文字列からの数値抽出で、if文とsubstringを組み合わせて力技で書いてしまった経験はありませんか。
今回はJavaで文字列のパターンマッチングを行う正規表現(文字列のパターンを記号で表現する仕組み)と、それを扱うPattern・Matcherクラスを解説します。
Pattern・Matcherとは?
正規表現とは何か
正規表現とは、「数字が3つ続く」「@を含む」のような文字列のルールを、決まった記号(メタ文字)で表現する仕組みです。
Javaではjava.util.regexパッケージのPattern(正規表現をコンパイルして保持するクラス)とMatcher(実際に文字列と照合するクラス)を組み合わせて使います。
Pattern・Matcherの役割分担
- Pattern:正規表現の文字列を
compileメソッドでコンパイルし、再利用可能な形にする - Matcher:
Patternと実際の対象文字列を渡して、一致判定・検索・置換を行う
同じパターンを何度も使う場合はPatternを先にコンパイルしておくと、毎回文字列から正規表現を解析するより効率的です。
基本の書き方
文字列が形式に一致するか判定する
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexSample {
public static void main(String[] args) {
String email = "katsu-coach@example.com";
String regex = "^[\\w.+-]+@[\\w-]+\\.[a-zA-Z]{2,}$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(email);
boolean isValid = matcher.matches();
System.out.println(isValid); // true
}
}
Pattern.compileで正規表現をコンパイルし、matcherメソッドで対象文字列を渡したMatcherを作ります。matches()は文字列全体がパターンに完全一致するかどうかを判定します。
文字列から部分一致を検索する(find)
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String text = "注文番号は12345です。担当者コードは987です。";
Pattern pattern = Pattern.compile("\\d+"); // 数字の連続
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println("見つかった数字: " + matcher.group());
}
// 見つかった数字: 12345
// 見つかった数字: 987
matches()が「全体一致」なのに対し、find()は「文字列の中から部分一致する箇所を順番に探す」動きをします。whileループでfind()を呼び続けると、一致するすべての箇所を取得できます。
正規表現による文字列の置換
import java.util.regex.Pattern;
String text = "TEL: 090-1234-5678, 080-9999-0000";
String masked = text.replaceAll("\\d{2,4}-\\d{2,4}-\\d{4}", "***-****-****");
System.out.println(masked); // TEL: ***-****-****, ***-****-****
StringクラスのreplaceAllメソッドは内部でPattern・Matcherを使っているため、簡単な置換ならこちらの方が手軽です。
個人情報のマスキング処理などで、正規表現による一括置換はよく使われます。
よくあるつまずきポイント・エラー対処
バックスラッシュのエスケープを忘れてPatternSyntaxException
実際に私が電話番号のバリデーションを書いたときにハマった経験ですが、正規表現の文字列を書くときにJavaの文字列エスケープを忘れて意図しない動きになったことがあります。
// ❌Before:\dをそのまま書いてしまい、意図と違う動作になる
String regex = "\d{2,4}-\d{2,4}-\d{4}"; // コンパイルエラー
Pattern pattern = Pattern.compile(regex);
このコードはjava: illegal escape character in string literalというコンパイルエラーになります。
Javaの文字列リテラルでは\dのような正規表現のメタ文字を書くとき、Java自身のエスケープ文字\と衝突するため、\\dのように二重にエスケープする必要があります。
// ✅After:バックスラッシュを二重にしてJavaの文字列として正しく渡す
String regex = "\\d{2,4}-\\d{2,4}-\\d{4}";
Pattern pattern = Pattern.compile(regex);
「正規表現は書けているのにコンパイルエラーになる」ときは、まずバックスラッシュのエスケープ漏れを疑うとよいでしょう。
応用・一歩先の使い方
グループ化して一部だけ取り出す
import java.util.regex.Matcher;
import java.util.regex.Pattern;
String log = "2026-08-31 ERROR ファイルが見つかりません";
Pattern pattern = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}) (\\w+) (.+)");
Matcher matcher = pattern.matcher(log);
if (matcher.matches()) {
System.out.println("日付: " + matcher.group(1));
System.out.println("レベル: " + matcher.group(2));
System.out.println("メッセージ: " + matcher.group(3));
}
()で囲んだ部分はグループとして扱われ、group(1)のように番号を指定して個別に取り出せます。
ログ解析のように「決まった形式の文字列から項目ごとに値を抜き出したい」場面で活躍します。
Stream APIと組み合わせた一致件数のカウント
import java.util.List;
import java.util.regex.Pattern;
List<String> words = List.of("apple123", "banana", "cherry99", "grape");
Pattern pattern = Pattern.compile(".*\\d+.*");
long count = words.stream()
.filter(pattern.asMatchPredicate())
.count();
System.out.println(count); // 2
Pattern.asMatchPredicate()を使うと、正規表現をStream APIのfilterにそのまま渡せるPredicateとして使えます。
まとめ
この記事のポイント
- 正規表現は
Pattern(コンパイル済みパターン)とMatcher(照合実行)の組み合わせで扱う matches()は全体一致、find()は部分一致の検索に使う- 正規表現内のバックスラッシュはJavaの文字列として
\\と二重に書く必要がある - グループ化(
())で一致した文字列の一部だけを取り出せる
次に読むべき記事
- Scannerで入力を受け取る
- シリアライズの基本
タグ: Java, 中級者向け, 標準ライブラリ