JavaのPatternクラスは、正規表現(Regular Expression)のパターンを表すクラスです。
正規表現とは、文字の並び(パターン)を表現する一つの方式で、特殊文字(メタキャラクタ)などを使って、効率よく文字列の検索や操作が行える大変便利な機能です。
Javaに限らず多くのプログラミング言語では、正規表現を扱うクラスが用意されており、また「秀丸エディタ」や「サクラエディタ」などのテキストエディタでも、正規表現を使って検索や置換が行えます。
【関連記事】
▶初心者でもわかる!Java正規表現の書き方【サンプルあり】
Patternクラスで正規表現を定義
Javaで正規表現を扱う場合は、まずjava.util.regex.Patternクラスに使用する正規表現を定義しコンパイル後、Matcherクラスなどを使用して、対象とする文字列が正規表現に一致しているかなどを調べます。
では、Patternクラスに正規表現を定義するサンプルコードを見ていきましょう。
次の例は、英字のa-zのいずれかにマッチする正規表現を、Pattern.compileメソッドに指定して、指定した正規表現をコンパイルしたPatternクラスを作成する例です。
Pattern pattern = Pattern.compile("[a-z]");
Matcherで正規表現にマッチさせる
Patternクラスを作成したら、次は作成した正規表現のPatternクラスに文字列をマッチングさせてみましょう。
正規表現のマッチングは、Pattern.matcherメソッドに対象となる文字列を渡してMatcherクラスのインスタンスを取得し、正規表現にマッチしたかどうかを調べます。
Pattern pattern = Pattern.compile("[a-z]");
String target = "こんにちは Java";
// matcherにマッチングさせる文字列を渡してMatcherのインスタンスを取得
Matcher matcher = pattern.matcher(target);
// 正規表現にマッチしたかどうかは、Matcher.find()メソッドで調べられる
if (matcher.find()) {
System.out.println("正規表現にマッチしました。");
} else {
System.out.println("マッチしませんでした。");
}
無効な正規表現をPatternに指定すると例外が発生
Pattern.compileメソッドに無効な正規表現(構文として正しくない正規表現)を指定すると、PatternSyntaxExceptionの例外が発生します。
//閉じ括弧がない無効な正規表現を指定
Pattern pattern = Pattern.compile("[a-z");
// 無効な正規表現パターンを指定すると次のような形で例外が発生する
// Exception in thread "main" java.util.regex.PatternSyntaxException: Unclosed character class near index 3
// [a-z
// ^
特殊文字(メタキャラクタ)のエスケープ
正規表現には、[] {} | . + * ? () ^のような特殊文字(メタキャラクタ)が存在し、たとえば「+」の場合、直前の1文字の1回以上の繰り返しを表現する特殊文字です。
特殊文字自体を、検索対象とする場合はエスケープを行う必要があり、特殊文字の前に\(バックスラッシュ)を挿入します。
また、Javaで\(バックスラッシュ)を使用する場合も、エスクケープする必要があるため、実際には特殊文字の前に2つの\(バックスラッシュ)を挿入します。
// (+)という文字を検索できるように、\で特殊文字をエスケープしたPatternを作成
Pattern pattern = Pattern.compile("\\(\\+\\)");
String target = "今回のテスト結果の判定は(+)です。";
Matcher matcher = pattern.matcher(target);
// 上で作成した正規表現にマッチング
if (matcher.find()) {
System.out.println("正規表現にマッチしました。");
} else {
System.out.println("マッチしませんでした。");
}
【実行結果】
---------------------
正規表現にマッチしました。
正規表現で\(バックスラッシュ)を検索する場合もエスクケープが必要です。
正規表現でマッチした文字列を取得
Matcher.group()メソッドを使用して、正規表現にマッチした文字列を取り出すことができます。
次のサンプルコードは、数値が4つ以上続く文字列にマッチする正規表現の「[0-9]{4,}」を指定してPatternクラスを作成し、Matcher.group()で対象文字列から正規表現に一致した部分を取得する処理です。
Pattern pattern = Pattern.compile("[0-9]{4,}");
Matcher matcher = pattern.matcher("Tokyo2020Olympic");
if (matcher.find()) {
String matchString = matcher.group();
System.out.println("「" + matchString + "」の部分にマッチしました");
}
1つ注意点があり、Matcherクラスのgroupメソッドを呼ぶ前に、findまたはlookingAt、matchesのいずれかを呼んで正規表現とマッチングさせておく必要があります。
これらのメソッドを呼ばずに、いきなりgroupメソッドを呼び出すとIllegalStateExceptionの例外が発生します。
括弧を使って正規表現をグループ化
括弧内に正規表現を指定し、括弧内の文字列をグループとしてひとまとめに扱うことが可能です。
例えば、郵便番号の前3桁と後4桁をグループ化する正規表現は次のように書きます。
(\d{3})-(\d{4})
また、グループ化した正規表現でマッチさせた文字列は、matcher.group(index)メソッドに先頭が1から始めるグループ(括弧)のインデックスを指定して、グループにマッチした文字列を取り出せます。
実際に、先ほどの郵便番号の正規表現を使って、グループにマッチした文字列を取得してみるサンプルコードを作成してみましょう。
Pattern pattern = Pattern.compile("(\d{3})-(\d{4})");
Matcher matcher = pattern.matcher("東京都庁の郵便番号は「163-8001」です。");
if (matcher.find()) {
System.out.println("group(0)=" + matcher.group(0));
System.out.println("group(1)=" + matcher.group(1));
System.out.println("group(2)=" + matcher.group(2));
}
【実行結果】
------------------------
group(0)=163-8001
group(1)=163
group(2)=8001
このように、インデックスに0を指定してgroupメソッドを呼ぶと、正規表現にマッチした文字列全体が取得でき、1以降のインデックスを指定すると、指定した位置のグループ(括弧)にマッチした文字列が取得できます。
さいごに
ここまで紹介したように、正規表現は効率よく文字列の検索や操作が行える大変便利な機能です。
おそらく今回の記事で紹介した内容を、正規表現を使わずにJavaのコードで書いた場合は、数十から数百行のコードとなり、メンテナンス性も非常に悪いコードになるでしょう。
正規表現の利用シーンは、プログラミングだけにとどまらないため是非覚えておきましょう。
ユーザーが入力した正規表現を、Pattern.compileメソッドに指定する場合など、無効な正規表現が指定される可能性がある場合は、適切に例外処理を行いましょう。