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
}
}
ここでは正規表現の基本的なメソッド、使用方法について説明しました。