金宏 和實(かねひろ かずみ)

 富山県高岡市 株式会社イーザー副社長。本当に暑い夏でしたね。私の会社では暑さのピークのときにエアコンが壊れました。ウィーンと唸るサーバーに囲まれ,汗だくで仕事をしました。また,ある休日は36度の熱気のなか,住民運動会で小学校PTAの活動資金稼ぎのために売店をしていました。少し涼しい風が吹き始めるころに夏バテで調子を崩すことがありますので,気を付けたいと思います。皆さんもどうぞご自愛くださいませ。

 今回は,正規表現(regular expression)を使った入力チェックについて解説したいと思います。正規表現は,UNIX互換OSを使っている人や,PerlやJavaでプログラミング経験がある人には,当たり前の機能だと思いますが,VBプログラマにはあまりなじみのあるものではないかもしれません。正規表現は記号の複雑な組み合わせになることが多いので,とっつきにくい呪文のように感じている人もいるかもしれませんね。

 正規表現は,入力内容のチェックや文字列から特定の文字列の抽出・置換,文字列の分割などに利用することができます。今回は,正規表現を使うことのメリットを,フォームでの入力チェック処理を中心に説明します。

 正規表現を使うと,複雑なチェックが簡単にできるのです。いきなり,正規表現の文法について説明すると,面倒に感じてしまうかもしれないので,実例から見ていきましょう。

入力チェックの仕様を考える

図1●ライントレース競技会の参加チームと競技結果を記録するアプリケーションの入力フォーム
図1●ライントレース競技会の参加チームと競技結果を記録するアプリケーションの入力フォーム

 第5回,第6回とロボットのライントレース競技会の参加チームと競技結果を記録するアプリケーションの開発を例に説明を進めてきました(図1)。その入力フォームにも正規表現でチェックするといいだろうなと思う項目がたくさんあります(表1)。

表1●入力項目と内容
項目 入力内容 備考
NO 0から9999までの整数値 半角数字(1桁以上4桁以内)のみ入力可能とする
タイム -999.99から999.99までの正負実数 ハイフン(-)と小数点(.)の入力を認める。小数点以下が00の場合は小数点以下は入力しなくてもよい
電話番号 ハイフン付きの固定電話/携帯電話の番号(フリーダイヤルをのぞく) 東京03-XXXX-XXXX,富山市076-XXX-XXXX,高岡市0766-XX-XXXX,携帯090-XXXX-XXXX,080-XXXX-XXXXの形式。フリーダイヤルのように最後のブロックが2桁や3桁で終わる番号は認めない
メールアドレス アルファベット(大文字/小文字),数字,およびドットなど記号の一部。ローカル部とドメイン部は@で区切られる。メールアドレスの先頭と末尾がドットでない hogehoge@example.com,
hogehoge@hoge.example.com,
hogehoge.hage@hoge.example.comなどの形式

 許可する値を考えてみると,チェックすべき内容が意外に難しいことに気づいていただけるかと思います。電話番号やメールアドレスが正しいかどうかは,最終的には電話をかけてみたり,メールを送ったりしないとわからないのですが,形式として正しいかどうかはできるだけチェックしないといけませんね。

 正規表現で入力内容をチェックするためのフォームを作成しました(図2)。

図2●正規表現で入力内容をチェックするためのフォーム
図2●正規表現で入力内容をチェックするためのフォーム

 このフォームには,表2に示したテキストボックスを配置しました。いきなり電話番号やメールアドレスの正規表現を考えるのは難しいので,郵便番号を間に追加してみました。郵便番号としては,999-99999と999-99,そして,999の三つの形式を認めたいと思います。

表2●テキストボックス一覧
テキストボックス 内容 認める値の範囲/形式
txtNO 整数値 0~9999
txtZipCode 郵便番号 999-9999,999-99,999(9は数字を意味する)
txtTime 正負実数 -999.99~999.99
txtTelNo 電話番号 09-9999-9999,099-999-9999,099-9999-9999,0999-99-9999(9は数字を意味する)
txtMail メールアドレス hogehoge@example.com,
hogehoge@hoge.example.com,
hogehoge.hage@hoge.example.com

 まず,正規表現を使わないで,txtNOのチェック処理を作成してみましょう(リスト1)。


Private Sub txtNo_Leave(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles txtNo.Leave
  If txtNo.Text = "" Then
    Exit Sub
  End If
  Try
    txtNo.Text = Integer.Parse(txtNo.Text)
  Catch ex As FormatException
    MessageBox.Show("数値を入力してください")
    txtNo.Focus()
    Exit Sub
  Catch ex As Exception
    MessageBox.Show("正しい数値を入力してください")
    txtNo.Focus()
    Exit Sub
  End Try
  If txtNo.Text < 0 Or txtNo.Text > 9999 Then
    MessageBox.Show("0から9999の範囲で入力してください")
    txtNo.Focus()
    Exit Sub
  End If
End Sub
リスト1●正規表現を使わない,txtNOのチェック処理

 今回の例では,テキストボックスを離れるとき(Leave時)に,値のチェックをしています。最初のコードは,何も入力されていないときに,チェックを抜けるためのif文です。

 整数値であるかどうかをチェックするために,Integer型のParseメソッドで32ビット符号付き整数,つまりIntegerに変換します。Try~Catchブロックで挟んであるので,Integerとして解析できないときは,例外を拾い,エラー・メッセージを表示します。例えば,数値以外を入力するとFormatExceptionが発生するので「数値を入力してください」とメッセージを出力します(図3)。

図3●数値以外を入力すると,エラー・メッセージを表示
図3●数値以外を入力すると,エラー・メッセージを表示

 ここまでのステップではまだ,負の値や4桁を超える値,-123や12345などが入力できてしまいます。NOとして負の値は不適切だし,桁数に「長い短い」があるとわかりにくくなります。

 そこで,変換がうまく行ったら「txtNo.Text < 0 Or txtNo.Text > 9999」として値の範囲をチェックしています。

 この方法でも,まずいことは何もありません。しかし,正規表現を使うと,同じチェック処理をもっとシンプルに記述できるのです。

RegexクラスのIsMatchメソッドを使う

 VB 2005で正規表現を使うには,RegexクラスのIsMatchメソッドを使用します。RegexクラスはSystem.Text.RegularExpressionsネームスペースにありますので,コードの先頭でネームスペースをインポートします(リスト2)。


Imports System.Text.RegularExpressions
Public Class Form2
    ・
    ・
    ・
  If Regex.IsMatch(txtNo.Text, "^[0-9]{1,4}$") Then 
    ' マッチ 何もしない
  Else
    ' 入力エラー
    MessageBox.Show("0から9999の範囲で数値を入力してください")
    txtNo.Focus()
    Exit Sub
  End If
リスト2●IsMatchメソッドを使った例

 RegexクラスのIsMatchメソッドは,正規表現のパターンにマッチする対象が文字列内で見つかるかどうかを調べます。この例の場合,^[0-9]{1,4}$というパターンに一致する文字列がtxtNo.Textの中に見つかるとIsMatchがTrueを返します。

 パターンを構成する特殊な意味を持つ文字をメタキャラクタ(メタ文字)と言います。パターンに合致するかどうかをチェックすることをマッチングすると言います。

 図4は,正規表現によるパターンマッチングのイメージです。^[0-9]{1,4}$というパターンで,0から9999の範囲の数字が入力されていることをチェックできるわけです。[0-9]とか{1,4}についてはなんとなく値の範囲と長さかなと思えますが,「^」や「$」が何を意味するのかは想像がつかないでしょう。

図4●正規表現によるパターンマッチングのイメージ
図4●正規表現によるパターンマッチングのイメージ