知らずに落ちると抜け出せなくなるVBAの落とし穴です。
- Len関数がなぜか4を返す
- 文字列の切り取り・切り抜きなどの処理がうまくいかない
- 数字の桁数を調べるのがうまくいかない
あたりにお悩みの方は、この落とし穴に落ちていないかご確認ください。
Len関数の仕様
Len関数には、「String以外の変数を渡すと、変数のメモリ上の大きさを返す」というクソの役にも立たない仕様があります。
Debug.Print Len("1234567") ' = 7 ← これがやりたい Long型の変数 = 1234567 Debug.Print Len(Long型の変数) ' = 4 ← 4バイトの大きさの変数という意味 String型の変数 = 1234567 Debug.Print Len(String型の変数) ' = 7 ' ← Stringに入っていれば数値でもOK
ということで、Len関数を「変数に対して使用」する場合は、
かならずStringの変数を使ってください。
数値だからとLongを使うと、絶対に4を返すクソ関数化します。
数値が何桁か調べるときに発生することが多そうですのでお気を付けを。
Long型の変数が何桁か調べたい場合は、
Debug.Print Len(Long型の変数 & "") ' = 7 Debug.Print Len(CStr(Long型の変数)) ' = 7
このように「""を結合する」「Cstr関数で文字列にする」のいずれかで対応します。
あとは頻度はあまり高くありませんが、文字列の操作中に発生すると面倒ですね。
文字列処理は複雑で読みづらいコードになっていることが多く、
「おっかしーなー、ここはMidだから○○になってるでしょ?
で、次のLeftで△△になってるはずで~……」
と無駄な脳内デバッグを強いられ、
発見時に言いようのない疲労に襲われる可能性があります。
「文字列中の数値を抜き出す際に、抜き出した数値をLong変数に入れる」
場面くらいしか発生パターンはないかもしれませんが、一応気を付けておきましょう。
変数の型ごとの細かい仕様
各変数の型に対する、細かい仕様については以下の通りです。
Long型の変数 = 1234567 Debug.Print Len(Long型の変数) ' = 4 ← 4バイトの大きさの変数という意味 Long型の変数 = "1234567" Debug.Print Len(Long型の変数) ' = 4 ← 暗黙の型変換されるので文字列にはならない String型の変数 = 1234567 Debug.Print Len(String型の変数) ' = 7 ← Stringに入っていれば数値でもOK Variant型の変数 = 1234567 Debug.Print Len(Variant型の変数) ' = 7 ← VariantはStringだと思ってくれる
' A1セルに1234567と入っている Debug.Print Len(Range("A1")) ' = 7 ← 変数じゃないのでそのまま文字数 Set Range型の変数 = Range("A1") Debug.Print Len(Range型の変数) ' = 7 ← 規定のプロパティ「Value」を見る Set Object型の変数 = Range("A1") Debug.Print Len(Object型の変数) ' = 7 ← Object変数にRangeを入れても同じ Set Variant型の変数 = Range("A1") Debug.Print Len(Variant型の変数) ' = 7 ← Variant変数にRangeを入れても同じ ' B1セルに日付形式で「4月1日」が入っている Set Range型の変数 = Range("B1") Debug.Print Len(Range型の変数) ' = 10 ← 「2020/04/01」の10。やはりValueを見ている Debug.Print Len(Range型の変数.Text) ' = 4 ← 「4月1日」を数えるならTextプロパティで ' C1セルに「あいうえおかきくけこ」と入れておく Set Characters型の変数 = Range("C1").Characters(2, 5) Debug.Print Len(Characters型の変数) ' ← これはエラー。文字っぽいけどCharacterはオブジェクト
とりあえず一番大事なのは、Variant型は大丈夫という点です。
Variant型は、値であればString型とみなしてくれるので、
数字が入っていようと、文字数をカウントしてくれます。
他には、セル値の文字数をLenでカウントするのはたまにやりますので、
こちらも気に留めておいてください。
といっても、「オブジェクト型変数のメモリ数を返す」ような罠はなく、
どのように書いてもセルのValueプロパティの文字数を素直に見てくれるので、
気に留めておかなくても、普通に使って困ることはないかもしれません。
ということで、結論としては「数値だけ気を付けておけばOK」と言ってもいいですね。
何桁の数字か?小数点以下何桁あるか?
あたりでDoubleとかLongを使わないようにしておけば、
罠にかかることはまずないということです。
ちなみに「オブジェクト変数に対するLen関数の動き」ですが、
常に「オブジェクトの既定のプロパティの文字数を数える」ようです。
Charactersに対して使った際も、オブジェクト変数のメモリ上の大きさは返さず、
既定のプロパティを取得できなかったときに出るエラー
「オブジェクトはこのプロパティまたはメソッドをサポートしていません」
を出します。
他にどうでもいい仕様として、Double型が8を返すとかありますが、
その辺は割愛します。
知りたくなった方は、適当に調べてください。
おまけ:謎のエラーメッセージ
ベタ打ちの値にLen関数を使った際、
Len("1234567")と、わざわざ文字列であると明記していました。
これを、
Debug.Print Len(1234567)
こう書くと、
変数が必要です |
と言われます。
今回説明した仕様を知らないと、なんのこっちゃというメッセージですが、
「文字列(String)ではない ⇒ ってことは変数?でもそんな変数ないよ?」
という意味のメッセージですね。
しゃーない。変数が必要と言われたら作りますか。
Dim 1234567 As Long
自分で「数字始まりの変数名は禁止」しておきながら、
「1234567は文字列じゃない。ってことは変数だな。」
とか、所詮はロボットですね ┐(´∀`)┌
まあこれは「値を直接入れる」という、めったにない処理での話であり、
Variant型の変数 = 1234567 Debug.Print Len(Variant型の変数) ' = 7
と、前述の通りVariantは、Stringと思って気を利かせてくれます。
それならまあ、許してあげましょう。