Visual Basic 6.0 テクニック
VB6対応

 

Visual Basic 中学校 > VB6 テクニック >

9.入力チェック論2 チェックする方法

 

概要

・入力された値が数値かどうかチェックする方法

・IsNumeric関数は "3D2" 等で True を返すので要注意

・入力された値に半角文字が存在するかチェックする方法

・入力された値のバイト数をチェックする方法

・その他、日付や特定の文字・複雑な入力チェックの方法

 

1.数値チェック

 

入力された値が数値かどうかチェックするにはどうしたよいでしょうか?ある程度VBをやったことのある人なら標準で用意されている IsNumeric関数を思い浮かべるでしょう。VB開発環境からイミディエイトウィンドウを開いて次のように入力することでこの関数をテストできます。(「イミディエイトウィンドウ」を開くには [表示]メニューから[イミディエイトウィンドウ]をクリックします)。

? IsNumeric("12345")

画像1(イミディエイトウィンドウ):イミディエイトウィンドウでは関数などをテストすることができる。

Enterキーを押すとイミディエイトウィンドウに True と表示されるでしょう。12345は数値として評価できますから当然の結果です。念のため次のようなテストもして見ましょう。

? IsNumeric("ABCDEFG")

これはもちろんFalseです。

というわけで数値のチェックにはIsNumeric関数が使えそうに思えますが、実はIsNumeric関数の性質を知っていないと後で痛い目を見ることになります。

たとえば、驚いたことに次の式は True を返します。

? IsNumeric("3D2")

実際、CDbl("3D2")を実行すると 300 を返します。この他に"3E2"などもTrueを返します。しかしいくらVBの数値関数で変換できる値だからといっても 3D2 を数値として扱うのは困る場合の方が多いと思います。

IsNumeric関数がTrueを返す注意すべてき例を表に掲げておきます。

IsNumeric関数が True を返す値の例
123.56
123,56
1,,,,,,6
.56
+123
-123
123+
123-
3E2
3D2

この表のような値をそのままデータベースの数値型項目にセットしようとすれば、エラーになる可能性は大きいですから、IsNumeric関数が使えるシーンというのは結構限られてくることになります。

IsNumeric関数に頼らない数値チェックは次のような形になります。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応
Private Function IsDigit(ByVal Value As String) As Boolean

    Dim K As Long

    If Len(Value) = 0 Then
       
IsDigit = False
       
Exit Function
   
End If

        For K = 1 To Len(Value)
        If
Not Mid(Value, K, 1) Like "[0-9]" Then Exit
Function
   
Next K

    IsDigit = True

End Function

この関数を使えば文字列が純粋に数字のみで構成されているかどうかをチェックできます。たとえば、IsDigit("12345")はもちろんTrueで、IsDigit("ASDF"), IsDigit("+123"), IsDigit("3E2")はいずれもFalseを返します。

 

2.半角チェック

 

全角文字を受け付けたくない場合もよくあります。そうするとどこかで入力された文字列に全角文字が混ざっているかそうじゃないのかチェックする必要があります。みなさんはこのようなチェックをどう書いていますか?

結論からいって次のようになります。

VB6対応   

Private Function IsMultiByte (Value As String) As Boolean

    Dim LetterCount As Long        '文字列の文字数

    Dim ByteCount As Long            '文字列のバイト数

    LetterCount = Len(Value)

    ByteCount = LenB(StrConv(Value, vbFromUnicode))

    If LetterCount <> ByteCount Then  IsMultiByte = True

End Function

この関数は「半角文字のみで構成される文字列はその文字数とバイト数が等しい」とうい事を利用して全角文字が含まれているかどうか判定しています。

具体的には文字数は有名な Len関数で取得。バイト数は LenB関数で取得できるのですがちょっと工夫が必要です。とういのはVBは内部では文字列をすべてUnicode(ユニコード)として扱っているため半角文字も全角文字もすべて2バイトなのです。このためそのまま LenB(Value)などとやってもLen(Value)を2倍した値が返ってくるだけです。

そこで、LenBを使う前に文字列をUnicodeから変換します。それが StrConv(Value, vbFromUnicode) です。

まぁこのようなちょっとしたポイントはありますが全体としては平易なものでしょう。いかがでしたか?みなさんもこうやっていましたか?

念のためこの関数の使用例も書いておきましょう。

IsMultiByte("ASD123")False を返します。その他 IsMultiByte("ASDあいう"), IsMultiByte("かきく")などはすべてTrueを返します。

 

3.アルファベットチェック

 

アルファベット以外は入力してほしくないという場合は次のようにチェックします。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応

Private Function IsAlphabet (Value As String) As Boolean

    Dim K As Long

    If Len(Value) = 0 Then Exit Function

    For K = 1 To Len(Value)

        Select Case Mid(Value, K, 1)

            Case "a" To "z"

            Case "A" To "Z"

            Case Else

                Exit Function

        End Select

    Next K

    IsAlphabet = True

End Function

この例ではループをまわして一文字ずつチェックしています。

特に変わったことはやっていないのでまぁ分かっていただけると思います。 なお、この関数はアルファベットでも全角の場合はFalseを返します。Trueを返させるにはどうすればいいかはわかりますよね?

また、この場合にもLike演算子を使って次のように書くこともできます。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応

Private Function IsAlphabet (Value As String) As Boolean

        Dim K As Long

        For K = 1 To Len(Value)

                If Not Mid(Value, K , 1) Like "[a-zA-Z]" Then Exit Function

        Next K

        IsAlphabet = True

End Function

数値チェックのところにある例と比べるとほとんど同じということがわかるでしょう。違うのはLike演算子の右側が"[0-9]"から"[a-zA-Z]"になっていることだけですね。Like演算子の持つ柔軟性がお分かりいただけると思います。

 

4.特定文字のチェック

 

特定の文字だけ入力を許可したい場合はもうアルファベットチェックの場合とほとんど一緒です。

ここでは A, S, D, 8 だけを許可するようなチェックの例を示します。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応

Private Function StrictLetter (Value As String) As Boolean

    Dim K As Long

    If Len(Value) = 0 Then Exit Function

    For K = 1 To Len(Value)

        Select Case Mid(Value, K, 1)

            Case "A", "S", "D", "8"

            Case Else

                Exit Function

        End Select

    Next K

    StrictLetter = True

End Function

特定の文字だけ拒否する例は挙げるまでもないでしょう。

さて、この例をLike演算子を使った例に直すと次のようになります。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応

Private Function StrictLetter (Value As String) As Boolean

        Dim K As Long

        For K = 1 To Len(Value)

                If Not Mid(Value, K , 1) Like "[ASD8]" Then Exit Function

        Next K

        StrictLetter = True

End Function

 

 

5.バイト数チェック

 

入力できる文字数を制限したいというのもよくあることです。この場合Len関数でチェックすればすぐ済むのでここではこの解説はしません。ここではLen関数だけではすまないバイト数のチェックを説明します。

といっても半角チェックのところで解説したロジックを使うだけです。

つぎの関数で文字列のバイト数を取得できます。

VB6対応

Private Function ByteCount(Value As String) As Long

ByteCount = LenB(StrConv(Value, vbFromUnicode))

End Function

解説は2.半角チェックのところをご覧ください。

ちなみに、文字数のチェックは MaxLengthプロパティに値を入れておけば自動的にやってくれます。たとえば、Text1のMaxLengthプロパティに 6 をセットすると後は何もプログラムしないでもText1には6文字以上入力できなくなります。ただし、これは「文字数」の制限であって「バイト数」の制限ではない点に注意してください。

 

6.日付チェック

 

VB初級プログラマが一番悩むのは日付チェックでしょう。まず、入力された文字列が有効な日付かどうかチェックする必要があります。これはVBにあらかじめ用意されている IsDate関数を使えば簡単にできます。この関数は同時にうるう年チェックもやってくれるので IsDate("2001/2/29")などはちゃんとFalseを返してくれます。

この他の日付に関するちょっとしたコード例は当サイトのサンプルにおいてありますので日付処理でお困りの際は一読くださると幸いです。

さて、 このように入力された値が日付として有効かどうかは簡単にチェックできますが実際にはもうちょっと別のチェックが必要になることがあります。たとえば、月末のみ入力可能にしたい場合です。

ちょっと説明が分かりにくいと思うのですが「月末のみ入力可能にしたい場合」は普通、ユーザーには年と月だけを入力させますからチェックの必要はありません。でも、プログラムの内部では入力された年と月から月末の日付を取得する必要があります。ですから、「入力チェック」というのとはちょっとちがうのですが、こういうところで汚らしいコードを書く人が多いので特に ここでサンプルを提供します。

次の関数は、年、月をもとに月末の年月日を返します。

VB6対応 VB.NET2002対応 VB.NET2003対応 VB2005対応

Private Function LastDay(TargetYear As Long, TargetMonth As Long) As Date

LastDay = DateAdd("D", -1, DateSerial(TargetYear, TargetMonth + 1, 1))

End Function

このように月末の日付を得るのにごちゃごちゃした条件判断など一切必要ありません。うるう年でも大丈夫です。この関数は LastDay(2001, 2) では 2001/2/28 を返し、 LastDay(2000, 2)では 2000/2/29 を返してくれます。

一応解説すると、次の月の1日から1日ひいた日付を返しているだけです。たとえば、2000年6月の月末を得るには、2000年7月1日の1日前を見ればいいという発想です。

日付型がサポートされているVB特有のロジックです。活用しない手はありません。

 

7.複雑なチェック

 

以上で基本的なチェックは一通り解説したと思いますが実際にはこれらを組み合わせたようなチェックが必要になるシーンがほとんどです。たとえば、1文字目は半角アルファベットの大文字であとは3桁の数値のみ許可するというチェック。"A100"や"G599"はよくても、"1234"や"125F"はだめというわけですね。

このようなチェックは桁数に応じたチェックをする関数を用意しておけば足りますが、その関数は私は示しませんので皆さんで試してみてください。実際それほど難しくありません。

しかし、世の中にはさらに複雑なチェックもあります!このような複雑なチェックを全部まとめて面倒を見てくれる便利なものはないでしょうか?「そんな都合のいいものないよ」と最初からあきらめていませんか?実はあるのです!

それは、RegExp オブジェクト です。

ここではRegExp オブジェクトの使い方、どのようにして複雑なチェックができるのかを解説します。

なお、RegExp オブジェクトを使うにはMicrosoft Internet Explore 5.0 以上が必要です。RegExp オブジェクトを単体でインストールすることも可能なようですがそっちのほうはよくわかりません。

それでは、RegExp オブジェクトを使ったサンプルアプリケーションを作ってみます。

RegExp オブジェクトを使うにはまず、[プロジェクト]メニューから[参照設定]で、Microsoft VBScript Regular Expressions 5.5 にチェックを入れます。(5.5の部分は環境によって異なっているかもしれません)。なお、一覧にこれがない人はRegExp オブジェクトがインストールされていない人です。

次にフォームにテキストボックス1つとコマンドボタン1つを配置します。名前はデフォルトのままでText1, Command1にしてください。このText1に入力された文字列をCommand1をクリックしたときにチェックするようにします。

用意ができたらCommand1にクリックイベントのところに次のように記述してください。

VB6対応   

Private Sub Command1_Click()

    Dim RE As New RegExp

    RE.Pattern = "^[A-Z]*[0-9]+[A,E]$" '正しい入力例を「正規表現」で指定する。

    If RE.Test(Text1.Text) Then
        MsgBox "入力は正しい"
    Else
        MsgBox "誤りがあります"
    End If

End Sub

以上で終わりです。今回は「大文字アルファベット0文字以上から始まって数字が1つ以上続き、最後にAかEがつくかどうか」というやや複雑なチェックを行います。たとえば、"A120E", "5A", "SSD20A"などはよくて、"A50", "AE", "456" などはだめです。

実行しテキストボックスにいい例と悪い例を入れて試してみてください。ちゃんと判断しているでしょう?これはどうやっているのでしょうか?

もっとも重要なのが RE.Pattern = "[A-Z]*[0-9]+[A,E]"  の部分です。 この "[A-Z]*[0-9]+[A,E]" が先ほどの条件「大文字アルファベット0文字以上から始まって数字が1つ以上続き、最後にAかEがつく」を表現しています。ですからこの表現を変えれば他の複雑なチェックも任せられます。

この表現は「正規表現」という規則にしたがって記述する必要があります。今回の例を解説すると [A-Z]* は「0文字以上のアルファベットの大文字」という意味で、[0-9]+ は「1文字以上の数字」、[A,E]は「AまたはE」を意味しています。

このほかの「正規表現」について知りたい人はインターネットの検索に「正規表現」といれて検索してみてください。親切に解説してくれているサイトがあるものですね。

この正規表現は別に入力チェックのためにあるのではありませんが、今回の例のように複雑な入力チェックに応用することができるというわけです。RE.Pattern = "[A-Z]*[0-9]+[A,E]"の部分を変えればいろいろなパターンでチェックできるわけですからこの部分を関数化することもできますね。

RegExp オブジェクトや正規表現の解説はMSDNライブラリにもちゃんと日本語で用意されているのでそちらを参照してもいいでしょう。ただ、あまり初心者向けじゃないので、ある程度VBができる人だけご覧ください。

なお、今までもでてきたLike演算子を使用すると正規表現のチェックと似たようなことができます。 しかし、この例をLike演算子をつかった例に置き換えるのは結構大変です。なぜなら、Like演算子では「何文字か続く」という表現ができないからです。つまり正規表現にはLike演算子を上回る柔軟性と表現力があるということです。正規表現が使える環境の場合は正規表現による入力チェックは一考の価値があります。

 

8.最後に

 

今回はRegExp オブジェクトに解説のところがやや目新しいのですが、その他は基本事項の確認といったところですね。 今回は解説しませんでしたがクラスやユーザーコントロールを使ってさらなる入力チェックの効率化を図ることもできます。興味のある方は是非試してみてください。