見出し画像

自己紹介:私のVBAの書き方

はじめまして。周囲にVBAを書ける人がいない環境で、エクセルと格闘しているうちに、VBAが書けるようになりました。ここでは、私の独自のVBAの書き方についてご紹介します。そして私がどう考えてVBAを書いているかを解説する記事を投稿していきたいと思います。

よくわからないことは覚えない

vbaに関する本やwebをみると、「コレクション」「オブジェクト」「ステートメント」「クラス」「private sub」などの言葉が並びます。プログラミング言語に精通している人はすぐに理解するのでしょうが、学生時代に縁遠かった自分にはイマイチ理解できていません。解説もさらっと読みますが、それを人に伝えられるほどではない。
それでも特に困っていません。オブジェクトという概念が分からなくても、特定の範囲を設定するときは set を使って range でセルを指定することなど、必要なことはそのうち覚えます。
エラーが起きて何でだろう、と調べて、「set」忘れてた、と頭に刻み込むことを繰り返せば覚えます。
というかしょせん、人間の脳はそんなかたちでしか記憶しないと思います(中年というか初老の域に入っているからかもしれませんが)。

R1C1形式しか使わない

range("B5") などという書き方を紹介しているwebは多数あります。多数のデータを扱ったり、ワークシートでデータの整理をしてから、vbaで読み込ませようとするときに、特定の列や範囲を指定していたらずれてしまいます。ワークシートでの作業は列を増やして関数でつなげながらつくっていくことが多いからです。だから、特定の範囲をA1形式で指定することはありません。
でも Range(cells(10,5),cells(15,8)) などと書いていては同じではないか、と思うでしょう。
そこで考えたのが、データの行は常に11行から開始する、必要な列番号は column 関数で、左上のA1あたりに集めておく、という方法でした。
必要なデータは列を固めればよいので、たとえば、colnum=cells(1,1).value として、以下のように書けばいいのです。

  • data1=cells(10+i , colnum+1).value

  • data2=cells(10+i , colnum+2).value

このように参照する列をワークシートのA1周辺に固めておけば、参照する範囲が作業でずれても問題なく参照できます。

ちょっと短い書き方は敢えてしない

vbaの解説をみていると、「こう書くと短くて済む!」というのがあります。例えば、InputBox は、Mirocosoft のページをみると「Application.InputBox メソッド」と書いているので「Application.InputBox」と書くのが正しいようですが、単に「InputBox」と書いているページも多いです。
関数も「WorksheetFunction.sum」などと書いているページがほとんどですが、これも正しくは「Application.WorksheetFunction.Sum」みたいです。
あとセルの値を求めるとき「.value」を書いていない解説も多いですね。まぁどっちでもいいのでしょうが、私は敢えて長いほうを書くことにしています。なぜなら、略してうまく動かなかったときに、動かない原因が変に略したことにあるケースがあるからです。
入力は大した手間ではありませんし、コピペで使えることも多いのですから、それでいいと思っています。

For~Next しか使わない

プログラミングで最も効率的なところはやはり繰り返し処理だと思います。繰り返し処理には「Do While ~ Loop 」「Do Until ~ Loop」「For ~ Next」の3種類がありますが、もっぱら使用するのは「For ~ Next」。ほかの2つもなんとなくは理解しているのですが、イマイチ使いたくない。解説でよく見る「i + 1= i 」というのが「なんで!」という気持ちになるから。
でも「For ~ Next」を使うためには何回処理するかをあらかじめ決めないといけないではないか、と思われるでしょう。
その辺は事前に計算して配列にしてしまう、という方法をとっています。
私的には「For ~ Next」のほうが、ワークシートの計算をイメージしやすいのです。

配列は常に1から

配列はvbaのなかでも中級者向けの概念だと思います。私も理解するのに時間がかかりました。でも「配列=概念上のセル範囲」だとイメージできれば、かなり使えるようになったと思います。
しかもワークシートは2次元限定ですが、3次元、4次元でもつくれるというのがすごい。まぁたいていは2次元で済んでしまいますが。
しかし、「配列は0から数える」というのが、最初頭を悩ませていました。プログラミング言語的には正しいのでしょうが、なじめないし、書いていて混乱してしまう。
でもあるページをみて(1 to i)などと書いているので、1からでもいいのか!と思い、以後、それで書いています。それで特に何の問題もありません。あと1からだと「For ~ Next」の書き方と整合がとれるので、コピペしやすいメリットがあります。

変数には一工夫

アルファベットでよく見る変数は「i」「j」ですね。何か決まりがあるのかは知りませんが。。。ただデータを分析するうえで変数が1つ2つで済む、というのはほとんどありません。そんな簡単なデータだったら、別に関数でできてしまうからです。よって多数の変数をアルファベットで設定すると、ワークシート上でデータを読み込むとすると、以下のような状況になります。

データの数=a
データのある列=b
データ開始行=c
for-next で使う変数=d
データを格納する配列 arr()

redim arr(1 to a)
for d=1 to a
arr(d)=cells(c+d-1,b).value
next d

a ~ dの4つだけなら問題ないですが、別のデータを読むときにはそれぞれ設定する必要があるので、だんだん訳がわからなくなります。これでは自分でもチェックが難しいです。

そこであるとき気づきました。定数的に使うのはaa,bb,ccなど二つ書くようにしてはどうかと。定数 const で別途定義するという方法もありますが、それは面倒ですし、定義の dim 部分は別途書いておいて、コピペすればいいので、a~z、aa~zz まであってもかまいません。
そしてこの方法のほうが、for next 構文でイメージしやすいのです。「あ、これはデータ数がaaだから「for a=1 to aa 」と書けばいいなと。こうすれば、データ数とfor-next で使う変数が連動しますし、配列の要素数にも使えます。
そうすると、データを読み取る列も「colaa」と設定してしまえば、わかりやすい。つまりデータ量に対応した一連の変数にすることでイメージしやすくする方法です。
もちろん、データ数にあたる aa も別途ワークシート上で計算して、シートのA1当たりで読み取れるようにしておきます。
でも、データ開始行は変数ではなく固定します。必ず11行からとします。そうすれば、何も考えなくても、 10+a と行数を指定できるからです。以上の考えを踏まえて、私はいつもこう書いています(Dim は省略しますが、ほぼ long です)。

aa=cells(1,1).value
colaa=cells(2,1).value
redim arr(1 to aa)
for a=1 to aa
arr(a)=cells(10+a,colaa).value
next a

別に i でもいいのですが、すぐ別のデータを読み込むのですから、i にこだわる必要もありません。私は a から使っています。

終わりに

以上のように、私はかなり我流でvbaを書いています。膨大なデータをワークシート上の関数でつなげてデータを整理していくことを数年前までやっていましたが、ファイルサイズが大きくなると動きも重くなります。また、元データが更新され、レコード数が増えると、計算行もコピペで増やしたりしないといけないとか、small などの関数はどうしても限界があるとか、いろんな制約に気づいて、vbaを書くことが増えた次第です。
もちろん、私のやり方は邪道だ!とか、美しくない!という方もおられると思います。まぁネット上の解説をみながら独自に編み出したものなので、それは当然です。でも自分なりに工夫を重ねてきたので、割といい線いっているかな、と思っている次第。何かご意見いただければ幸いです。















この記事が気に入ったらサポートをしてみませんか?