【Java】Javaの正規表現(Pattern・Matcher)の基本と使い方

Java

こんにちは、かつコーチです。
メールアドレスの形式チェックや文字列からの数値抽出で、if文とsubstringを組み合わせて力技で書いてしまった経験はありませんか。
今回はJavaで文字列のパターンマッチングを行う正規表現(文字列のパターンを記号で表現する仕組み)と、それを扱うPatternMatcherクラスを解説します。

Pattern・Matcherとは?

正規表現とは何か

正規表現とは、「数字が3つ続く」「@を含む」のような文字列のルールを、決まった記号(メタ文字)で表現する仕組みです。
Javaではjava.util.regexパッケージのPattern(正規表現をコンパイルして保持するクラス)とMatcher(実際に文字列と照合するクラス)を組み合わせて使います。

Pattern・Matcherの役割分担

  • Pattern:正規表現の文字列をcompileメソッドでコンパイルし、再利用可能な形にする
  • MatcherPatternと実際の対象文字列を渡して、一致判定・検索・置換を行う

同じパターンを何度も使う場合は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, 中級者向け, 標準ライブラリ

タイトルとURLをコピーしました