正規表現

正規表現とは

ある文字列に対して、「XXで始まって○○で終わる」や「○○または△△またはXXを含む」、「□の後に○△が続く」などの複雑な検索や置換を行うパターンをチェックする方法です。

例えば、日本の郵便番号にマッチするかどうかを調べるコードは、以下のようになります。
「com.cmps.regex」パッケージを作成し、その中に「Regex」クラスを作成してください。

// 郵便番号
String postCode = "123-4567";
        
if (postCode.matches("[0-9]{3}-[0-9]{4}")) {
 System.out.println("マッチします");
} else {
 System.out.println("マッチしません");
}

正規表現はマッチさせる文字のパターンを表現します。
上記の例では「”^[0-9]{3}-[0-9]{4}$”」がパターン(正規表現)になります。

正規表現を利用することで、E-mail アドレスや URL、 HTML のタグなど、より複雑な文字列のパターンを抽出したり置換したりすることができます。

正規表現のパターンなんてすべて把握することはむずかしいですが、ネットで「Java 正規表現」とでも調べたらたくさん情報はありますし、正規表現パターンもたくさん出回ってますので、そう困ることはありません。
ただ「正規表現」という存在を知らないことはまずいので覚えておいてください。

正規表現の記号と意味

主な正規表現の記号と意味については以下の表の通りです。

記号記号の説明使用例説明
.任意の一文字。
改行文字は除く
b.nbanやb-n、binなどの場合該当
*直前の1文字が0回以上発生ba*nbn、ban、baanなどが該当
+直前の1文字が1回以上発生ba+nban、baanなどが該当
^行の先頭^ban行頭にbanがある場合該当
$行の末尾ban$文末にbanがある場合該当
[]カッコ内の任意の1文字と一致。
「-」で範囲指定が可能
①[123]
②[1-3]
1、2、3のいずれかがある場合該当
[^]カッコ内に含まれない1文字と一致[^ban]b、a、n以外の文字の場合該当
{n}直前の文字がn回発生。
nは整数。
ba{3}nbaaanの場合該当
{n,}直前の文字をn回以上発生。
nは整数。
ba{2,}baa、baaa、baaaaなどの場合該当
{n,m}直前の文字をn回からm回まで繰り返す。
nとmは整数。
ba{2,4}baa、baaa、baaaaの場合該当
|直前もしくは直後のパターンに一致bn|banbnもしくはbanの場合該当
?直前の1文字が0もしくは1個のパターンに一致ban?baもしくはbanの場合該当
()グループ化。()内のパターンは(グループ)と見なされる。

本単元の最初に書いていただいた「”^[0-9]{3}-[0-9]{4}$”」ですが

先頭の「^」は文字列の最初にマッチすることを意味します。

[0-9]は、半角数字の0から9までのいずれかにマッチするという意味です。
続く{3}は、それが3回続くという意味です。
続く「–」は、半角のハイフンそのものを意味します。
[0-9]{4}は、0から9の半角数字が4回続くという意味です。

最後の「$」は文字列の最後にマッチすることを意味します。

つまり、この正規表現パターンは、「0から9の半角数字3文字で始まり、次にハイフンがあり、0から9の半角数字4文字で終わる文字列」にマッチすることになります。

参考サイト:【5分でまるっと理解】Java正規表現についてのまとめ
参考サイト:【Java】正規表現のまとめ

下記の正規表現パターンにマッチするように文字列を設定して実行しましょう。
■電話番号

^[0-9]{2,4}-[0-9]{2,4}-[0-9]{3,4}$

■メールアドレス

^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$

Pattern

正規表現パターンで文字列を検索するには、Pattern/Matcherクラス(java.util.regexパッケージ)を利用します。

最初に文字列としてパターンを定義したあと、パターン文字列から Pattern オブジェクトを取得します。そして Pattern オブジェクトが対象の文字列とマッチするかどうか調べるのが Matcher オブジェクト( Matcher クラスのインスタンス)です。

// 検索する文字列を用意
String str = "東京都千代田区 123-4567";
        
// 正規表現のパターンを作成
Pattern pattern = Pattern.compile("[0-9]{3}-[0-9]{4}");
Matcher matcher = pattern.matcher(str);

正規表現のパターンオブジェクトを作るには、Patternクラスのcompileメソッドの引数に正規表現のパターンを指定します。次に、Patternクラスのmatcherメソッドの引数にパターンとマッチさせる文字列を指定してMatcherオブジェクトを作成します。

上記の例では、文字列である「東京都千代田区 123-4567」と正規表現のパターン「[0-9]{3}-[0-9]{4}」のMatcherオブジェクトを作成しています。

Matcher

実際に対象の文字列がパターンとマッチするかどうかを調べる役割をするのが Matcher オブジェクトです。これは Matcher クラス( java.util.regex.Matcher )のインスタンスです。

Matcher クラスにはコンストラクタが用意されておらず、 Pattern クラスのクラスメソッドである matcher メソッドを使ってインスタンスを取得します。

findメソッド

Matcherクラスのfindメソッドを使うことで、文字列が正規表現のパターンに一致するかをチェックすることができます。
Matcherクラスのfindメソッドは、文字列の中に正規表現のパターンが含まれる場合に”true”を返し、それ以外の場合には”false”を返します。

Patternの箇所で作成したソースに以下の一文を追記しましょう。

System.out.println(matcher.find());

trueが出力されました。
これは、文字列「東京都千代田区 123-4567」の中に、正規表現のパターン「[0-9]{3}-[0-9]{4}」が含まれているためです。

matchesメソッド

Matcher クラスの matches メソッドは対象の文字列全体がパターンにマッチするかどうかを調べます。

// 検索対象文字列
String str2 = "あいうえお";
Pattern maches = Pattern.compile(str2);
        
// パターン1
Matcher matches = maches.matcher("あいうえお");
System.out.println(matches.matches());
        
// パターン2
Matcher matches2 = maches.matcher("あいう");
System.out.println(matches2.matches());

パターン1では、文字列「あいうえお」とmatchesメソッドの引数で指定した文字列が一致しているため、「true」を返しています。

パターン2の場合、matchesメソッドの引数で指定した文字列は「あいう」で、文字列「あいうえお」と全体で一致しないため「false」が出力されます。

lookingAtメソッド

lookingAt メソッドは、対象の文字列の先頭からパターンとマッチするかどうかを調べます。先頭文字からマッチする必要はありますが、 matches メソッドのように文字列全体とマッチする必要はありません。

String str3 = "埼玉県";
Pattern samplePattern = Pattern.compile(str3);
        
// パターン1
Matcher m1 = samplePattern.matcher("埼玉県さいたま市");
System.out.println(m1.lookingAt());
        
// パターン2
Matcher m2 = samplePattern.matcher("さいたま市埼玉県");
System.out.println(m2.lookingAt());

パターン1では、文字列「埼玉県」と対象の文字列「埼玉県さいたま市」を調べて、対象の文字列の先頭からマッチしているため「true」を返します。

パターン2は対象の文字列が「さいたま市埼玉県」のため、先頭文字が「埼玉県」ではないため「false」を返します。

練習問題

「com.cmps.regex」の中に「RegexQuestion」クラスを作成してください。

問1: 文字列の先頭から4桁「0」の場合の正規表現を作成する。※「0000123456789」がOKになる

問2: 文字列が「png」、「jpg」、「jpeg」、「pdf」のいずれかの場合の正規表現を作成する。※「png」や「pdf」がOKになる

問3: 半角チェックの正規表現を作成しましょう。※全角が含まれていたらNGになる

問4: 書式チェックYYYY/MM/DDの正規表現を作成しましょう。
※「2022/12/30」がOKになる、ただし月日的に存在しないものはNGとする(4/31や2/30はNG。うるう年は考慮しなくてよい)。正規表現を29日までの月、30日までの月、31日までの月の3パターンに分けても良いです。

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