序文
Excel VBAにおいて、空白セルかどうかや変数が未代入かどうか等を判定したいというシチュエーションはそれなりにあると思います。しかし、一口に「無い状態を判断する」といっても、Emptyという識別子、Isemptyという関数、空白の文字列""、0、False、そして何も入力されていないセル等、VBA上で「入って無いと我々が認識できる何か」は色々あります。
この知恵ノートでは、様々な「入っていない状態」についてそれぞれ = で結びつけた時にどれとどれがTrueになるのか等、「無い」に関する判定結果を纏めてみました。
(Excel以外のWordやAccessといった他のOffice製品でも同じだとは思います。ただし、Accessに関してはフィールドなどに有効な値がない時はNull判定になるらしいので御注意下さい)
これで、「入力されていない」という判定をしたいのに思った通りにならない! といった問題から皆様が解放される事を祈っています。
早見表
http://yahoo.jp/box/Sklyl5
元になったExcelファイルはこちら
http://yahoo.jp/box/BhK6RG
実験方法
- Excel 2013でMicrosoft Visual Basic for Applications 7.1を起動して実験。
- 基本的に、「左側に入力した内容 = 上側のタイトル行の内容」で判定して条件式がTrueになるかFalseになるかを纏めています。(Cells(1,1).Value = "" や Empty = 0 等)
- Cells().Textにおいては、表示形式は標準です。
- IsEmpty等の関数に関しては、関数の括弧内に左辺の内容を入れてそれがTrueを返すかFalseを返すかを確認しています。(IsEmpty(False) 等)
各項目の概要(詳細については後述)
- Empty : Empty値です。 空白セルの値やVariant型変数の初期値でもあります。
- Isempty() : IsEmpty関数です。 引数の値がEmpty値の場合はTrueを返します。
- "" : 長さ0の文字列(空白の文字列)です。 文字が何も入っていない状態とも言えますが、下記のvbNullStringとはStrPtr関数での戻り値が異なります。
- 0 : 数字としての0です。Long型などの初期値で、文字列と比較するとエラーになります。
- "0" : 文字列としての0です。 String型に0を代入した場合はこちらです。
- False : 論理値の偽です。 Boolean型の変数の初期値です。
- vbNullString : String型変数の初期値であり、文字列が初期化されていないという状態です。宣言したてのString型変数はローカルウィンドウでの表記が""となっていますが、正確にはこちらのvbNullStringが初期値です。StrPtr関数での戻り値が""とは違って0となります。
- StrPtr() : StrPtr関数は引数のメモリ上でのアドレスを返す関数です。vbNullStringの場合0が返ります。InputBoxでキャンセルが押されたかどうかの判定によく使われます。
- Len() : Len関数は引数の文字数を返します。文字列型(Variant型)以外の変数を引数とした場合は変数のバイト数が返ります。(例えばLong型の場合は何桁であろうと4が返る)
- Null : いわゆる「使用できない」といった意味合いの特殊な値です。Excel VBA上ではわざわざ代入しない限りはほとんど出番は無いでしょう。 Accessの場合はフォーム等に有効な値が入っていない場合にNullとなるらしいので注意してください。
- Cells().Value : Valueプロパティはシート上のセルで計算された結果の値を取り出します。実験ではCells(1,1).Valueといった形で使用しています。 データ型はVariantです。
- Cells().Text : Textプロパティはシート上に表示されている文字をそのままを取り出します。セルの書式設定の[表示形式]の影響を受けます。 データ型はStringです。
- Cells().Formula : Formulaプロパティはセルに入力されている数式を取り出します。
データ型はStringです。
注意
- 変数・識別子の項目においては、左辺をVariant型の変数に入力すると結果が表と異なる場合があります。例えば「"" = 0」の判定では「型が違います」のエラーになりますが、Variant型の変数に "" を代入したりして「Variant変数 = 0」で条件式を判定するとエラーにならずにFalseになります。 恐らく、VBAの自動で型を変換する機能のせいだと思われます。
要点および特に注意すべき判定
空白セルかどうかはIsEmpty関数で判定
空白セルのValueプロパティはEmpty値を返します。なのでセルが空白かどうかを見るならば、IsEmpty関数で判定してTrueが返るか否かで判定すると良いでしょう。(以下A1セルの場合)IsEmpty(Cells(1,1).Value)
シートをVariant型の二次元配列に格納した場合でも、各要素が空白セルだったかどうかを判定するには、同様にIsEmpty関数で判定すべきです。
Variant型が初期値かどうかの判定もIsEmpty関数で判定
Variant型の変数は、宣言した後何も代入しなければ初期値はEmpty値になっています。そしてIsEmpty関数は本当にEmpty値か否かだけしか判断しません。なので、Variant型の変数に何も代入されていないかを判定する際はこれもIsEmpty関数で判定すると良いでしょう。IsEmpty(Variant変数)
= Empty で判定するとTrueになる範囲が広いので注意
空白セルから空白の文字列、0、False、その他初期値の変数全般が、Empty値 と = で結ばれます。なので、Empty値かどうかで条件分岐を作る事はオススメしません。逆にいえばこれだけ広い範囲のどれかでも良いというならば = Emptyで判断しても良いかもしれませんが、あまりその様なシチュエーションがあるとは思えません。
セルの値が 0 かどうかを判定する際、空白セルやFalseも0の判定になる
0と空白セルとFalseを区別しないなら問題は無いのですが、本当に0 と入力されているセルだけを判定したい場合は、Len関数で1が返ってくるかと併用する事をオススメします。Cells(1,1).Value = 0 And Len(Cells(1,1).Value) = 1
Falseと0は基本的には同じ。Len関数併用で区別可能。
1つ前の項目に関連している話ですが、Falseの実態は0な為にFalseと0ではほぼ同じ結果が返ってきます。Excelシート上のセル値の「数値の0」と「Falseと返した結果」を区別したい場合は、これもLen関数を併用して確認すると良いでしょう。(↓A1セルがFalse値の場合にのみ真となる条件)
Cells(1,1).Value = False And Len(Cells(1,1).Value) = 5
各項目の詳細
Empty値
要点でも書きましたが、空白セル以外にも変数の初期値や0(False)、空白の文字列などもEmpty値と = で結ばれて真という判定になります。Variant型以外の変数が初期値かどうかを調べるのに使えるかもしれませんが、Emptyでなくともその変数に対応する初期値をそのまま条件式に使用しても問題無いのです。(以下の二式は同じ)(宣言したての)Long変数 = Empty
(宣言したての)Long変数 = 0 ・・・Emptyでも0でも同じ
Empty値を代入以外で使える所はどこか?となると、数字としての0と文字列としての"0"を区別したいぐらいでしょうか。ただし、それにしても変数の型を調べる専門の関数であるVarType関数やTypeName関数と併用という手段があります。
IsEmpty関数
前述の要点で述べた通り、空白セルかどうかを調べるならこれです(Variant型の変数にRange().Valueを使用してセルのデータを二次元配列で格納した際も同様です)。またVariant型の変数が初期値のままかどうか調べるのも、IsEmpty関数が良いです。
ちなみに、Variant型以外の変数にEmpty値を代入してもIsEmpty関数はFalseを返します。
Long変数 = Empty
IsEmpty(Long変数) ・・・Falseが返る
長さ0の文字列 ""
文字列が何も入っていないかどうかを調べる際に使用します。宣言されたばかりのString型は""ではなくvbNullStringですが、「宣言されてから一度も代入されていないかどうか」をわざわざ調べたい場合(InputBoxでキャンセルが押されたかどうかを調べる場合等)以外ではこちらの""を使用して問題がないと思います。(文字打つのもvbNullStringより楽ですし。)なお、0やFalseと比較すると「型が一致しません」というエラーになりますので違う型と比較したい場合はVariant型変数に格納するか、文字列型に変更するCStr関数を使って下さい。
数字としての0
String型と比較してもVBAの自動型変換機能のおかげで、String型に数字が入っている場合はエラーになりません。(数字に変換出来ない文字や""との比較はエラーになります。)"1" = 0 ・・・Falseが返る
"a" = 0 ・・・「型が一致しません」のエラー発生
数字の0はFalseでもあり、さらに空白セルやEmpty値と = で判定するとTrueとなります。この為、「0という数値のみを判定したい(Falseや空白セルは除外したい)」場合は、前述の要点通りにLen関数との併用をお勧めします。 また文字列の"0"と区別したい場合はさらにEmpty値との比較か、型を調べるVarType関数やTypeName関数を併用して下さい。
0 = Empty And 0 = 0 And Len(CStr(0)) = 1 ・・・Trueが返る(Len(0)はエラー)
"0" = Empty And "0" = 0 And Len("0") = 1 ・・・Falseが返る
文字列としての"0"
数字の0と異なりString型変数に入れた"0"は、0以外とは殆どFalseです。ただし、"0" = False だけはTrueとなります。(でセルが =False() とかになっている場合、そのセルのValueプロパティと"0"を=で結んでもFalseになるというのはよく分かりませんが。)Falseとの区別をつけたい場合は、やはりLen関数との併用かEmpty値との比較等を行う必要があります。
String変数 = "0" And Len(String変数) = 1 ・・・"0"はTrueでFalseはFalse
False
基本的には0と同じです。 本当にFalseという文字かどうかを調べたい場合はLen関数と併用して下さい。 セルの場合は、Textプロパティで取得しても良いかもしれません。Trueについて
- VBAでは、True = -1 でTrue判定が返ってきます。TrueとFalseの判定の詳細に関しては下記リンク先を御参照下さい。
http://officetanaka.net/excel/function/tips/tips59.htm
vbNullString と StrPtr関数
String型の変数が宣言されたばかりで何も代入されていない場合、その初期値はvbNullStringです。 vbNullStringは空の文字列である""とほぼ同じ挙動をしますが、両者の違いはStrPtr関数の引数にいれた場合にvbNullStringのみが0を返すという点です。StrPtr関数は、vbNullStringを引数とした場合は0を、それ以外の何かを引数とした場合はメモリ上でのアドレスを返します(執筆者の環境では9桁の数字が返ってきました)
この違いはInputBox関数を使用した際に、キャンセルボタンが押されたのか何も入力されていない空の文字列のままOKボタンが押されたかの区別をつけたい場合によく利用されます。
InputBoxでキャンセルされたかどうかを判定する例
- Dim str As String
- str = InputBox("何か入力して下さい")
If StrPtr(str) = 0 Then
MsgBox "キャンセルされました"
ElseIf str = "" Then
MsgBox "何も入力されていません。"
Else
MsgBox "入力された文字は " & str & " です。"
End If
テキストボックスの空白
- [挿入]→[図形]で設置されたテキストボックス(Worksheets().Shapes().TextFrame.Characters.Textで値を取得)が空白の場合は空白の文字列""でした(vbNullStringではない)。
- また、[開発]→[挿入]で設置されたActiveXコントロールのテキストボックスや、ユーザーフォーム上に設置されたテキストボックス(TextBox1.Textまたは.Valueで値を取得)が空白の場合はTextプロパティでもValueプロパティでもvbNullStringでした。
Len関数
Len関数は、引数の文字列の文字数を返す関数です(全角も1文字判定)。Len関数を併用する事で、Empty値やFalse、0といったそのままだと区別出来ない場合があるパターンにおいて、区別する事が出来ます。Cells(1,1).Value = 0 ・・・空白セル、False、0、"0"がTrue
Cells(1,1).Value = 0 And Len(Cells(1,1).Value) = 1 ・・・0か="0"のみTrue
Len関数の引数に関する注意
- Len関数において文字列(String型、Variant型)以外を引数とすべきではありません。なぜならば、String型とVariant型以外の変数を引数とした場合は変数を格納するのに必要なバイト数(Boolean型なら2、Long型なら4、Date型なら8)を返すからです。
String型以外の変数を使用する場合は、CStr関数で型を変換すると良いでしょう。
Len(Long型変数) ・・・4が返る
Len(CStr(Long型変数) ・・・桁数が返る
Len(1) ・・・「変数が必要です」のコンパイルエラー
Null
Nullは「使用不可」、「無効」といった意味合いの特殊な値です。Nullが計算式・条件式等に含まれるとその結果もほとんどNullになります。Accessでは有効ではないフィールド等がNullになりますが、Excelでは明示的にNullを代入したりしない限りは殆ど出番はありません。例外として値が異なる複数のセルにまたがってRange().Textで値を取得すると、範囲に共通する部分がないという事でNullが返ってくる模様です。他にNullが返ってくる例としては、Switch関数で条件式に当てはまるものが無かったりした場合や、リストボックスが何も選択されていない状態でListBox.Valueを使用して値を取り出そうとするとNullが返ってきたりします(リストボックスが何も選択されていない状態でListBox.TextだとvbNullStringが戻り値)。
Cellsオブジェクト(Valueプロパティ、Textプロパティ、Formulaプロパティ)
前述しましたが、Valueプロパティはセルにある計算された結果の値を取り出し、Textプロパティはセル上に表示されている文字をそのまま取りだし、Formulaプロパティはセルに入力されている計算式を取り出します。TextプロパティとFormulaプロパティはString型の文字列として値を取り出すので、空白セルは空白の文字列 ""として扱われます。
ValueプロパティはVariant型なので、セルの結果値によって型は異なります。TypeName関数でCells().Valueの型を調べてみると、空白セルの場合はEmpty、数字の場合はDouble、文字列の場合はString、FalseとTrueの場合はBooleanになります。
Rangeオブジェクト
Range("A1:B1").Value などといった形で複数範囲のセルの値を確認しようとした場合、ValueプロパティとFormulaプロパティは「型が一致しません」のエラーが返ってきます。しかしTextプロパティだけは面白い事に、Rangeオブジェクト内のセルが全て同じ表示だった場合はその文字列を返してきます。そして1つでも表示が異なるセルが混ざっている場合、RangeのTextプロパティはNull値を返してきます。宣言したての変数
宣言したばかりの初期化されていない変数の規定値は以下の通りです。Vatiant型 : Empty値
Object型 : Nothing
Long等の数値型(Byte型含む) : 0
String型 : vbNullString
Date型 : 1899年 12月 30日 0時 0分 0秒 (シリアル値は0)
ExcelとExcel VBAのシリアル値
- Excelではシリアル値 1は1900年1月1日ですが、Excel VBAだとシリアル値 1は1899年12月31日です。
これに関してはExcelにある「本来存在しない 1900年2月29日が存在する」というバグとの摺り合わせのためだと思われます。
なので1900年3月1日以降は、ExcelとExcel VBAでシリアル値と西暦が一致します。
※西暦が4の倍数の年はうるう年ですが、100で割り切れる年はうるう年としない事になっています。しかしながら、400で割り切れる年だけはうるう年にします。 - 1900年は400で割り切れないが100で割り切れる年なので、4の倍数でもうるう年ではないのですが、Excelでは1900年2月29日が存在します(VBAでは存在しない)。