【Java】正規表現チェックを行う方法|PatternとMatcherの正しい使い方

【Java】正規表現チェックを行う方法|PatternとMatcherの正しい使い方 Java

Javaで開発をしていると、必ずと言っていいほど出てくるのが「入力値のチェック」である。

メールアドレス、電話番号、英数字、パスワード。
これらを正しく検証するために使われるのが、正規表現(Regular Expression)だ。

しかし、Javaの正規表現は初心者がつまずきやすい。

Pattern?
Matcher?
matches?
find?

ネットの記事も断片的な説明ばかりで、実務でどう書くべきかが見えてこない。

そこでこの記事では、Javaで正規表現チェックを行う方法を、基礎から実務レベルまで体系的に解説する。
Javaの正規表現は、正しく理解すれば非常に強力な武器になる。
逆に曖昧な理解のまま使うと、バグの温床になる。

ここで一度、きちんと整理しておくべきである。

【執筆者の簡易プロフィール】
江田島 執筆者:江田島
  • 43歳男性、既婚、1児の父
  • アプリケーションエンジニア
  • 大手受託開発企業に勤務中
  • Java一筋の職人(教え方はスパルタ気味)
  • 嫌いなもの:やる気のないエンジニア

Javaで正規表現チェックを行う基本構造

Javaで正規表現を扱う場合、基本となるクラスは2つだ。

  • Pattern
  • Matcher

この2つの役割を理解することが、すべての出発点になる。
まずは最も基本的なコードを見てほしい。

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Main {
public static void main(String[] args) {
String regex = "^[0-9]+$";
String target = "12345";

    // 正規表現をコンパイル
    Pattern pattern = Pattern.compile(regex);
    // 評価器を生成
    Matcher matcher = pattern.matcher(target);

    // 判定実行
    boolean result = matcher.matches();

    System.out.println(result);
}
}

このコードは「文字列が数字のみで構成されているか」をチェックしている。
出力結果は以下になる。

true

では、このコードが何をしているのかを分解して理解しよう。

Pattern:正規表現をコンパイルする

まず登場するのがPatternクラスである。

Pattern pattern = Pattern.compile(regex);

ここでは「正規表現の文字列」を解析し、内部的な「オブジェクト」を作っている。
言い換えるなら、正規表現の設計図を作る処理である。

重要なのはここだ。
Javaでは、正規表現は毎回解析されるとコストが高い。

そのため、Patternを使って事前にコンパイルする仕組みになっている。
この設計を理解していないエンジニアが多いため、無駄にPatternを何度も作るコードを書く。
それは非効率の極みだ。

正規表現は、再利用できるなら必ず再利用する。
これは実務の基本である。

Matcher:対象文字列を評価する

次に登場するのがMatcherクラスだ。

Matcher matcher = pattern.matcher(target);

これは「この文字列を、この正規表現でチェックする」という評価器を作っている。
つまり、「Pattern(設計図)」を「Matcher(検査員)」に渡してチェックさせる、という流れになる。

matches():文字列全体が一致するかチェック

最後に使うのが matches() メソッド。

boolean result = matcher.matches();

これは、「文字列全体が正規表現に一致するか」を判定する。

ここを誤解しているエンジニアが多いが、matches() は部分一致ではない。
完全一致 である。

例えば、正規表現が ^[0-9]+$(数字のみ)の場合、文字列が「123abc」なら結果は「false」になる。

matchesとfindの違いを理解していないコードは危険

Javaの正規表現でよくあるミスがこれだ。

「matches」と「find」の違いを理解していない。

この2つは全く意味が違う。

matches:全文一致

matcher.matches()

■意味:「文字列全体が正規表現に一致する」

例としては、正規表現 [0-9]+に対して、文字列「abc123」を判定すると、結果は「false」になる、ということが挙げられる。
なぜなら、文字列全体が数字ではないからだ。

find:部分一致

一方、find は違う。

matcher.find()

■意味:「文字列のどこかに一致する部分があるか」をチェックする。

例としては以下の通り。

String regex = "[0-9]+";
String target = "abc123xyz";

この結果は「true」になる。
理由は単純で、文字列の中に「123」という一致部分があるからだ。

この違いを理解していないコードは、実務では非常に危険である。
入力チェックでfindを使えば、簡単にバリデーションを突破されるバグが生まれる。

入力バリデーションではmatchesを使う。
これは覚えておくべき鉄則だ。

Pattern.matchesを使う簡易チェック

実はJavaには、もっと短く書く方法もある。
それがPattern.matches()である。

import java.util.regex.Pattern;

public class Main {
public static void main(String[] args) {
// コンパイルから実行まで1行で済ませる
boolean result = Pattern.matches("^[0-9]+$", "12345");

    System.out.println(result);
}
}

これは内部で「Pattern生成」「Matcher生成」「matches実行」をまとめて行ってくれる。

ただし注意点がある。
この方法は、毎回Patternを生成する。
つまり、大量処理では劇的に遅くなる。

■単発チェック → Pattern.matches
■繰り返し処理 → Pattern.compile(定数化して再利用)

これが正しい使い分けである。

Javaでよく使う正規表現チェック例

ここからは、実務でよく使う正規表現チェックを紹介する。

WordPressなどのCMS環境での表示崩れを防ぐため、バックスラッシュを伴う \d ではなく文字クラス [0-9] を使用した記法を用いる。

■数字のみチェック

String regex = "^[0-9]+$";

boolean result = Pattern.matches(regex, "123456");

文字列の開始から終了まで、すべて数字であることをチェックしている。

■英数字チェック

String regex = "^[a-zA-Z0-9]+$";

これは英字と数字のみを許可するパターンだ。
ログインIDなどの検証によく使われる。

■メールアドレスチェック
簡易的なチェックなら次で十分だ。

String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$";

ただし、正規表現だけで完全なメールチェックはできない。
実務では「簡易正規表現」と「メール送信確認」の2段階で検証するのが現実的である。

実務で正規表現を使うときの鉄則

最後に、現場で何度も見てきた失敗をまとめておく。
正規表現は便利だが、扱いを間違えると保守性が地獄になる。

正規表現は必ず定数に定義する

悪いコード。

Pattern.matches("^[0-9]{8}[A-Z]{3}$", text);

これでは何をチェックしているのか分からない。

良いコードは、こうなる。

private static final String PRODUCT_CODE_REGEX = "^[0-9]{8}[A-Z]{3}$";

Pattern.matches(PRODUCT_CODE_REGEX, text);

意味が分かる名前を付ける。
これはエンジニアの基本だ。

Patternは使い回す

これはパフォーマンスの話だ。

悪いコード(ループ内で毎回生成)。

for(String text : list){
Pattern.matches(regex, text); // 遅い
}

良いコード(事前にコンパイル)。

Pattern pattern = Pattern.compile(regex);

for(String text : list){
Matcher matcher = pattern.matcher(text);
matcher.matches();
}

まとめ

Javaで正規表現チェックを行う基本は以下の通りだ。

  • 正規表現はPatternでコンパイルする
  • Matcherで文字列を評価する
  • matchesは全文一致、findは部分一致
  • 繰り返し処理ではPatternを再利用する

正規表現は便利な道具だが、雑に使えばコードの可読性を破壊する。

短いから正義ではない。
読めるコードこそ正義である。

これを理解しているエンジニアだけが、正規表現を正しく「道具」として使いこなせる。

コメント

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