Java の正規表現の基礎

正規表現とは?

まずは、正規表現 (Regular Expression) とは何か、簡単に説明します。

正規表現は簡単に言えば「文字のパターンマッチング」と言えます。

例えば「AからZの文字2文字」とか「AからZの文字2文字に続いて数字5桁」とか、そういったものがパターンになります。

正規表現を使えば、例えば 「この文字列から数字の部分だけ抜き出したい」 とか 「このテキストファイルに含まれているメールアドレスだけ抜き出したい」 とか 「ユーザーが入力した文字が正しい URL の形式になっているかチェックしたい」 といった要望を満たすことができます。

「メールアドレスを抜き出したい」というときには、"メールアドレス" とはそもそもどんな文字列か? ということを定義します。

「メールアドレスなら、最初にアルファベットか数字が続いて、次に @ マークが来て、次にまたアルファベットか数字、または . が続く」

と考えたとします。

このとき、こうしたルールのことを「パターン」といいます。

正規表現では、このパターンを特定の文字列に適用して、パターンに合致するかしないかチェックすることができます。

正規表現の簡単な利用例

ではさっそく、正規表現の利用方法をみていきましょう。

次の例は、"NH105" という文字列が、[0-9]{1,3} というパターンにマッチするかチェックしています。

package com.keicode.java.test;

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

public class TestApp {
  public static void main(String[] args) {
    Pattern p = Pattern.compile("[0-9]{1,3}");
    Matcher m = p.matcher("NH105");
    // 結果を出力
    System.out.println("matches(): " + m.matches());
    System.out.println("find(): " + m.find());
  }
}

パターンを指定しているのは 8 行目です。

[0-9] という部分は「0から9までの数字1文字」の意味です。 {1,3}は 「1 文字から 3 文字の長さ」という意味です。

このことから、[0-9]{1,3} というパターンは「0から9までの数字が1から3文字並ぶ」という意味のパターンになります。

チェックする文字列 "NH105" では 105 の部分、確かに数字が3文字並んでいます。

このプログラムを実行すると、実行結果として次のようになります。

matches(): false
find(): true

matches() メソッドの呼び出しは false、find() メソッドの呼び出しは true となりました。これはどういうことでしょうか。

Java の matches() メソッドと find() メソッド

パターンは java.util.regex.Pattern で定義します。 Pattern.compile メソッドで、引数として受け取ったパターン文字列を元に、 Pattern オブジェクトを作成します。

ここでは [0-9]{1,3} というパターンを渡しています。

matcher() メソッドで適用する文字列を指定して、Matcher オブジェクトを取得します。 この Matcher オブジェクトを使って実際のパターンマッチング操作を行います。

matches() メソッドは、パターンを適用する文字列全体がパターン文字列と合致するかどうかチェックします。

ここでは "NH105" という文字全体が指定したパターンと合致するか、ということをチェックしたことになります。従って false となります。

find() メソッドはパターンを適用する文字列の中に指定したパターンが存在するかどうかチェックします。

ここでは "NH105" という文字列の中に指定したパターンが存在するかチェックしたことになります。105 の部分がパターンにマッチしますので true が返ります。

Java の正規表現の文字クラスとは?

正規表現では文字クラスといって、複数の文字をまとめて表現することができます。

例えば、「0, 1, 2, 3, ... , 9 のどれか」ということについては [0123456789] と書けます。

またこれは「0 から 9 のどれか」ということで [0-9] と書けます。

これを用いると「0 から 9 のどれかがひとつ以上」というパターンは [0-9]+ と書けます (+ はひとつ以上、* はゼロ以上を表します)。

package com.keicode.java.test;

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

public class TestApp {
  public static void main(String[] args) {
    Pattern p = Pattern.compile("[0-9]+");
    Matcher m = p.matcher("NH105");
    // 結果を出力
    System.out.println("find(): " + m.find());
    // find(): true
  }
}

「0 から 9」ということはすなわち「数字」ということで、特別な文字でパターンが表現できます。

[0-9] は \d と書いても同じです。

package com.keicode.java.test;

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

public class TestApp {
  public static void main(String[] args) {
    Pattern p = Pattern.compile("\\d+");
    Matcher m = p.matcher("NH105");
    // 結果を出力
    System.out.println("find(): " + m.find()); 
    // find(): true
  }
}

文字列の中では \ はエスケープするために \\ と二つ組み合わされています。

また「数字」クラスには特別な名前が付いていて {Digit} とも書けます。 これは事前定義文字クラス名 (predefined character class name) といいます。

パターン文字列中で事前定義の文字クラス名を表すためには、\p を用いますから、上記のコードを書き直すと次のようになります。

package com.keicode.java.test;

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

public class TestApp {
  public static void main(String[] args) {
    Pattern p = Pattern.compile("\\p{Digit}+");
    Matcher m = p.matcher("NH105");
    // 結果を出力
    System.out.println("find(): " + m.find());
    // find(): true
  }
}

他の事前定義文字クラスについては「Java の正規表現の文字クラス」に記載しました。

正規表現での大文字小文字の区別

基本的にパターン文字列は大文字と小文字を区別します。これをケースセンシティブであるといいます。

逆に大文字小文字を区別しない場合は、ケースインセンシティブといいます。

大文字小文字を区別しない場合は compile メソッドに Pattern.CASE_INSENSITIVE フラグを渡して次のようにします。

package com.keicode.java.test;

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

public class TestApp {
  public static void main(String[] args) {
    Pattern p = Pattern.compile(
        "CDE", Pattern.CASE_INSENSITIVE
    );
    Matcher m = p.matcher("abcdef");
    // 結果を出力
    System.out.println("find(): " + m.find());
    // find(): true
  }
}

ここでは正規表現の基本的なメソッド、使用方法について説明しました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Java 入門