前回(214話)からJavaによる正規表現について解説をしております。正規表現というのは解説本を買ってじっくり勉強するほどのボリュームはないものの,かといってWebサイトでパッと見て理解できるほど単純な仕組みではありません。「こうしろうのMindStorms日記」では2006年の年初企画としまして,数回に渡り正規表現を解説したいと思います。

 正規表現には,1.文字列がパターンに一致するか検証する。2.文字列から部分文字列を抜き出す。3.文字列のパターンに一致する部分を置換する。の三通りの役割があることは前回説明しました。今回も前回に引き続き,文字列の検証についてみていきましょう。

 先頭が特定の文字列で始まり,後ろは何でも構わないという検索はよくあります。

----------------------------------------------------------

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

public class RegTest2 {
 public static void main(String[] args) {
  String text ="abcdefghijk";
  String ptnStr = "^abcd\\w*";
  Pattern ptn = Pattern.compile(ptnStr);
  Matcher mc = ptn.matcher(text);
  System.out.print("1.1:");
  if(mc.matches()) {
   System.out.println(ptnStr+"にマッチします");
  } else {
   System.out.println(ptnStr+"にマッチしません");
  }

----------------------------------------------------------
 Javaで正規表現を使うにはJava.util.regex.Patternとjava.util.regex.Matcherクラスをインポートする必要があることは前回説明しました。

 注目してほしいのはptnStr の正規表現「^abcd\\w*」です。^は先頭を表すメタ文字です。abcdは普通のアルファベット文字,つまり,ここまでで文字列の先頭4文字はabcdであることを指定したわけです。\wはa~z,A~Z,0~9の英数字とアンダースコア(_)を表すメタ文字です。*はその\wに対応する文字が0個以上繰り替えすことを指定します。ですから文字列「abcdefghijk」はこの正規表現にマッチします。

 実行すると,
----------------------------------------------------------

 1.1:^abcd\w*にマッチします

----------------------------------------------------------
 と表示されます。

 先頭がabcdなら後ろは何でもよいと検索条件をもう少しオープンにしたいとき,たとえば,"abcdefghij k"のように空白文字を含む文字列にマッチさせたいときは,「^abcd.*」とパターン文字列を指定します。「.」は任意の文字にマッチしますので,空白文字もOKになります。

 先頭の一致があれば,当然末尾の一致もあります。末尾は「$」で表します。末尾がijkで終わるという正規表現は,たとえば「\\.*ijk$」のようになります。「abcdefghijk」などの文字列が一致します。
----------------------------------------------------------

  text ="abc";
  ptnStr = "a.c";
  ptn = Pattern.compile(ptnStr);
  mc = ptn.matcher(text);
  System.out.print("3.1:");
  if(mc.matches()) {
   System.out.println(ptnStr+"にマッチします");
  } else{
   System.out.println(ptnStr+"にマッチしません");
  }

----------------------------------------------------------
 ちょっと簡単な例に戻りましょう。文字列「abc」がa.cという正規表現に一致するのは,もうおわかりだと思います。しかし,文字列「ABC」はマッチしません。小文字と大文字を区別するからです。小文字(Lowercase)と大文字(Uppercase)を区別させないようにするには,以下のようにPattern.compileの行にCASE_INSENSITIVE(CASEを無視する)を指定します。
----------------------------------------------------------

ptn = Pattern.compile(ptnStr,Pattern.CASE_INSENSITIVE);

----------------------------------------------------------
 郵便番号のチェックを考えてみましょう。先頭から,数字3桁,ハイフンを挟んで,数値4桁で終わるというキチンとした郵便番号のチェックは以下のようになります
----------------------------------------------------------

  ptnStr = "^\\d{3}-\\d{4}$";
  text ="933-1234";
  ptn = Pattern.compile(ptnStr);
  mc = ptn.matcher(text);
  System.out.print("4:");
  if(mc.matches()) {
   System.out.println(text+"はマッチする");
  } else{
   System.out.println(text+"はマッチしない");
  }

----------------------------------------------------------
 933-1234は当然マッチしますが,他の形式は許しません。

 郵便番号の上3桁しかわからないときや,調べるのが面倒なとき,それからハイフンなんて必要ないだろうと言う理屈っぽい人,いろいろなニーズに答える正規表現を考えてみましょう。

 3桁(933),5桁(933-99),7桁(933-1234),ハイフンなし7桁(9331234)の郵便番号にマッチするパターンは,
----------------------------------------------------------

^\\d{3}(?:-?(?:\\d{2}|\\d{4}))?$
----------------------------------------------------------
 となります。ややこしそうに見えますが,3つのメタ文字を理解すればスッキリします。

1.(?:・・・)はグループ化,( )の中の?:の後ろが1つの固まりになると理解してください。

2.「?」は0個もしくは1個を示します。-?はハイフンが0個か1個を意味します。ハイフンの省略を認めているのですね。

3.「|」はOR(もしくは)です。\\d{2}|\\d{4}はハイフン以降の郵便番号が,2桁でも4桁でもよいことを意味します。

 本当に上記の全パターンが一致するかは,Eclipseを使って自分でプログラムを作って,試してみてください。