ユーザーフォーム上のテキストボックスの値を検証します.テキストボックスに入力する値のデータ型としては日付型,数値型,郵便番号や電話番号・メールアドレスなどの文字列型が主体です.日付型に関しては Excel 2003 までは Access® のカレンダーコントロールを流用できたのですが,最近のバージョンではそれもできなくなりました.キーボードからタイプするか,カレンダーを自作するか,関数アドインを利用するしかありません.
上図のようにフォーム上にテキストボックスを配置します.それぞれ TextBox1, TextBox2, TextBox3, TextBox4, TextBox5 としましょう.またコマンドボタンを配置し,Caption を OK に変更します.
形式的検証
検証には形式的検証と意味的検証とがあります.まず形式的検証についてです.未入力のチェックとデータ型のチェックが主体となります.両者のチェックのタイミングは別の方がよいでしょう.タイミングが異なるため,異なるイベントにすべきです.未入力のチェックは値が空白であるか否かだけを確認すれば良いため,一括して検証可能でしょう.となると個々のコントロールのイベントで都度チェックするのではなく,最後に登録するコマンドボタンが押された時点でよいということになります.逆にデータ型はコントロールごとに異なります.ですので個々のテキストボックスに入力が発生した時点で都度検証するのがよいでしょう.
意味的検証
意味的検証についてここでは詳述しませんが,単独のコントロールの入力値を検証するだけでなく,複数のコントロールの入力値同士を比較して検証する必要があったり,データベースに既に登録されたレコードの値と比較したりといった検証が必要になる場合もあります.そのような場合には個々のコントロールのイベントをフックするのではなく,最後に登録するボタンが押された時点で検証するのが妥当だと思います.そういったチェックは Access® の場合ですとテーブルに対するイベントとして登録する必要があります.
イベントの種類
話をイベントに戻します.では次にどのイベントを用いるべきでしょうか.意図しない入力が発生した場合は入力を確定させず,次のコントロールにフォーカスを移動させたくないのですから,Cancel 処理が入っているイベントが適切です.テキストボックスのイベントで代表的なものは下記のとおりです.
- BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
- Change()
- Exit(ByVal Cancel As MSForms.ReturnBoolean)
- KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
- KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
- KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Cancel 処理を持つのは BeforeUpdate と Exit です.Change イベントを始め他のイベントでは処理を止めるために自前でコーディングする必要があるでしょう.BeforeUpdate と Exit とでいずれが適切かは個々の要件によりますが,通常は BeforeUpdate でよいでしょう.それぞれのコントロールで BeforeUpdate イベントを選択した状態は下記のようになります.
Option Explicit Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) End Sub Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) End Sub Private Sub TextBox3_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) End Sub Private Sub TextBox4_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) End Sub Private Sub TextBox5_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) End Sub
検証の条件指定
次にデータ型をそれぞれ検証します.ここで強調したいのは,キャンセルする際の条件を満たした場合にキャンセル処理を行うコードを記述することです.その条件には,逆に入力を許可する条件式を指定しておき,最後に Not で条件式全体を否定するというちょっと複雑な処理が必要です.If … Then … ElseIf … と条件分岐を連ねていく方法もありますが,その都度キャンセル処理を書き連ねていく必要があります.ここは好みの問題かもしれませんが,ド・モルガンの法則からすると,And で条件を絞り込み,最後に Not で式全体を否定するのがスマートかと思います.そして Cancel = True としてキャンセル処理を実行します.では逆に入力を満たす条件をそのまま記述し,Cancel = False とすればどうなるでしょうか.これは宿題にしておきましょう.
データ型の検証
さて,話を戻します.各テキストボックスのデータ型は順に日付型,数値型,電話番号・メールアドレスおよび URL の文字列型です.TextBox1 から TextBox5 までいずれもキャンセル処理後フォーカスを残し,かつ入力した値全体を選択して即座にタイプできるようにしています.TextBox2 では非負の数値のみを受け付けます.
正規表現による文字列の検証
TextBox3 以降ではデータ型の検証をしていません.文字列型として扱う場合はデータ型を検証する必要がないからです.したがって入力された文字列そのものを検証する必要があります.TextBox3 では 11 桁の半角数値以外の入力を許可していません.TextBox4 においては正規表現を使って 44 行目のようにパターンにマッチさせる文字列を指定します.メールアドレスの正規表現によるマッチングはかなり複雑らしく,例文では不十分です.TextBox5 では URL にマッチさせます.メールアドレス同様,例文の検証法も不十分です.
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) With TextBox1 If Not IsDate(.Text) Then Cancel = True .SetFocus .SelStart = 0 .SelLength = Len(.Text) End If End With End Sub Private Sub TextBox2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) With TextBox2 If Not (IsNumeric(.Text) And .Text >= 0) Then Cancel = True .SetFocus .SelStart = 0 .SelLength = Len(.Text) End If End With End Sub Private Sub TextBox3_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) Dim myReg As Object Set myReg = CreateObject("VBScript.RegExp") With myReg .Pattern = "^[0-9]{11}$" .IgnoreCase = True .Global = True End With With TextBox3 If Not myReg.Test(.Text) Then Cancel = True .SetFocus .SelStart = 0 .SelLength = Len(.Text) End If End With End Sub Private Sub TextBox4_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) Dim myReg As Object Dim Pattern As String Pattern = "^[-a-z0-9]+(\.[-a-z0-9]+)*\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z0-9]{2,6}$" Set myReg = CreateObject("VBScript.RegExp") With myReg .Pattern = Pattern .IgnoreCase = True .Global = True End With With TextBox4 If Not myReg.Test(.Text) Then Cancel = True .SetFocus .SelStart = 0 .SelLength = Len(.Text) End If End With End Sub Private Sub TextBox5_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean) Dim myReg As Object Dim Pattern As String Set myReg = CreateObject("VBScript.RegExp") Pattern = "^https?://[a-z0-9][-a-z0-9]{0,62}(\.[a-z0-9][-a-z0-9]{0,62})*\.[a-z0-9][a-z0-9]{0,62}$" With myReg .Pattern = Pattern .IgnoreCase = True .Global = True End With With TextBox5 If Not myReg.Test(.Text) Then Cancel = True .SetFocus .SelStart = 0 .SelLength = Len(.Text) End If End With End Sub
参照:
サイト URL、フォルダ名、ファイル名に使用できない文字 (Microsoft®)
Active Directory 内のコンピューター、ドメイン、サイト、および Ou の名前付け規則 (Microsoft®)
ホスト名 (Wikipedia)
インターフェースとしてのEXCEL VBAによるユーザーフォーム