Excel VBA で プログラムの基礎を学ぶ!?
【環境】Windows 10 Pro 64bit、Excel for Office 365
プログラムの基礎と言ったら分岐と繰り返しと・・・と、なんだ?w
まー、そんなことは、どこかの偉い人が書いた文献でも読んで学んでください!
ざっくりと、プログラムを知らない、難しい?大変?なんですよねー?って、思ってる人に、簡単だよ!って教えるためのブレークタイムのような記事を書きますw
念のため、先に言うときますけど、ここに書かれていることは、真実ではない可能性があります
わしの考え方ですので、ちゃんとプログラムを知りたい人は、ちゃんと勉強してくださいねー!w
■基本的な要素
以下がプログラムの基礎的な要素になります!(言い切るスタイル!w)
- 変数(プロパティ)
- 関数(メソッド)
たった2つ・・そんなもんさ~
クラスだとか、オブジェクトだとか、型、列挙型、構造体、共用体、配列、引数、戻り値、ポインタ、アドレス、値渡し、参照渡しとか、色々な難しい言葉を耳にしたことがあると思います
でもね!肝になるのは「変数」と「関数」だけなんです!
「変数」を「関数」に渡すには【引数】を使うってだけで、【構造体】だって「変数」の組織だった集まりなわけでw
「変数」って何?「関数」って何?がわかってれば、プログラムなんてできるんですよー!(たぶんねw)
例)1+1=2
「変数」と「変数」を「関数」で処理したら新しい「変数」になるんですよー!的な?w
プログラムなんて、それの積み重ねですよ!
そりゃ、品質のいいプログラムを短時間で作成しようとしたら、センスだの経験だのって、色々必要なものはあるでしょうけど、そんなもんは、別世界の話です
・変数とは
「変数」ってのは、データの入れ物なんです!
「変数」は使い方が色々あって、元のデータを入れておくものもあれば、処理が終わった後のデータを入れておくものもある
それが、役割によって、引数だったり、戻り値だったり、配列や構造体だったり、名前や形状を変えてるだけで、要は「変数」ですw
・関数とは
「関数」ってのは、データを処理するんです!
「関数」は入力されたデータをどうにかこうにか処理して、あんな方法やこんな方法で出力するのです
条件による分岐や繰り返しを経て、計算や代入を行って、色々と異なる方法で出力されるだけなんです
■VBAで代入してみる
変数の使い方は、関数の中と外ではちょっと違います
・サンプルソース
Private aaa As String
Sub Func1()
Dim bbb As String
aaa = "AAA"
bbb = "BBB"
Call Func2(bbb)
End Sub
Private Sub Func2(ccc As String)
Dim bbb As String
Debug.Print "aaa = '" & aaa & "'"
Debug.Print "bbb = '" & bbb & "'"
Debug.Print "ccc = '" & ccc & "'"
End Sub
・コード説明
大したサンプルは書けませんが、簡単に説明します
- 1行目:ファイル内でのみ使用できる変数
- 3行目:ファイルの外からでも呼び出せる関数
- 4行目:関数内でのみ使用できる変数
- 6~7行目:変数にデータを代入
- 9行目:変数を関数に渡して呼び出す
- 13行目:ファイル内でのみ呼び出せる関数
- 14行目:関数内でのみ使用できる変数
- 16~18行目:それぞれの変数を出力
・出力結果
上記のサンプルプログラムでFunc1を実行すると以下の出力が得られます
aaa = ‘AAA’
bbb = ”
ccc = ‘BBB’
・出力の解説
- 変数:aaaは、ファイル内で使用できるので、関数:Func1で代入したデータの「AAA」が、関数:Func2でも参照できます
- 変数:bbbは、関数内でのみ使用できる変数なので、関数:Func1で代入していますが、関数:Func2ではデータは代入されていないので、空の文字列です
- 変数:cccは、関数:Func2の引数として、関数:Func1から、変数:bbbを渡されていますので、関数:Func1で代入したデータ「BBB」が参照できます
■処理 – 分岐
分岐というと条件が必要になりますが、関数で使われる処理では最も頻度がたかいでしょうか?そんな感じがします
VBAで使用する分岐をいくつか紹介します
・If…Then…Elseステートメント
基本的な条件分岐の「もし○○だったら××をする」です!
使い方はこんな感じで、①も②も③も書き方は異なりますが、全て同じ分岐で、同じ処理結果が得られます
Sub FuncIfElseThen(aaa As Integer)
' ①
If aaa = 1 Then
Debug.Print "aaaは1です"
ElseIf aaa = 2 Then
Debug.Print "aaaは2です"
Else
Debug.Print "aaaはそれ以外です"
End If
' ②
If aaa = 1 Then
Debug.Print "aaaは1です"
Else
If aaa = 2 Then
Debug.Print "aaaは2です"
Else
Debug.Print "aaaはそれ以外です"
End If
End If
' ③
If aaa = 1 Then Debug.Print "aaaは1です" Else If aaa = 2 Then Debug.Print "aaaは2です" Else Debug.Print "aaaはそれ以外です"
End Sub
③が長かったですが、これぞ「If…Then…Else」ステートメントの繰り返し!
※余談ですが、Ifの分岐を関数化した「IIf関数」というのもありますw
構文は、以下の通りですが、分岐ではなくあくまでも関数ですので、解説はしません
IIf(expr, truepart, falsepart)
上のサンプルソースと同じ結果を得るには以下のように記載します
Sub FuncIIf(aaa As Integer)
Debug.Print IIf(aaa = 1, "aaaは1です", IIf(aaa = 2, "aaaは2です", "aaaはそれ以外です"))
End Sub
・Select Case ステートメント
もう一つの分岐としては、「Select Case」ステートメントです!
使い方はこんな感じで、文字列を評価することも、評価に範囲や条件、変数を入れることもできます
Sub FuncSelectCaseString(aaa As String)
Dim bbb As String
bbb = "GGG"
Select Case aaa
Case "AAA": Debug.Print "aaaは'AAA'です"
Case "BBB", "CCC"
Debug.Print "aaaは'BBB'もしくは'CCC'です"
Case "DDD" To "FFF"
Debug.Print "aaaは'DDD'から'FFF'の間です"
Case bbb
Debug.Print "aaaはbbbと同じです"
Case Else
Debug.Print "aaaはそれ以外です"
End Select
End Sub
Sub FuncSelectCaseInteger(aaa As Integer)
Select Case aaa
Case 1: Debug.Print "aaaは1です"
Case 2, 3
Debug.Print "aaaは2か3です"
Case 4 To 6
Debug.Print "aaaは4~6です"
Case Is >= 7, Is < 10
Debug.Print "aaaは7~9です"
Case Else
Debug.Print "aaaはそれ以外です"
End Select
End Sub
IfThenElseステートメントは、ElseIf毎に別々の条件をかける(評価対象を変えれる)ので、分岐回数分の評価が行われるのですが、SelectCaseステートメントは、最初に1度評価するだけで、どのCaseに一致するかで処理されます
■処理 – 繰り返し
次は繰り返しですが、こちらも方法としては色々ありましてですねーw
これもVBAで使用するものを紹介します
・For…Next ステートメント
基本的な繰り返しと言えば「○○から××まで繰り返す」ですね!
使い方はこんな感じで、繰り返す範囲や1回の繰り返しの増減値を指定できたりします
Sub FuncForNext()
Dim idx As Integer
For idx = 0 To 10 Step 1
Debug.Print "idx = " & idx
If idx = 8 Then
Exit For
End If
Next idx
For idx = 10 To 0 Step -2
Debug.Print "idx = " & idx
Next
End Sub
条件によっては、繰り返しをやめたい場合には、「Exit For」で抜け出すことができます!
・For Each…Next ステートメント
もう一つのFor・・「For Each…Next」ステートメントです!
これは、配列やコレクションを指定して、そのグループを最初から最後まで繰り返してくれます
使い方はこんな感じで、あえて、見慣れたFileSystemObjectを使用してみました!
Sub FuncForEachNext(path As String, ptrn As String, data As Collection)
Dim fl As File
With New FileSystemObject
' pathのファイルを取得
For Each fl In .GetFolder(path).Files
' ファイルパターンに一致するものだけ取り出す
If (UCase(fl.name) Like UCase(ptrn)) Then
' Fileオブジェクトをコレクションに格納
Call data.Add(fl)
End If
Next
End With
End Sub
FilesプロパティはFileオブジェクトのコレクションですので、ForEachNextステートメントで取り出す場合、Fileオブジェクト型の変数でのみ取り出すことことができます(ちょっとだけ嘘ですがw)
「For Each」と「In」の間の受け側の変数は、「In」の後ろの変数(コレクション)に内包された型の変数でのみ取り出せる!というのかな???
ま、型が一致してないとダメって、怒られます!?(これも微妙に違うw)
配列でFor Eachを使う場合、バリアント型の配列じゃないと・・
Sub FuncForEachNextNG()
Dim var As String
Dim str(3) As String
Dim i As Integer
For i = 0 To 3
str(i) = Trim(i)
Next i
For Each var In str
Debug.Print Trim(var)
Next
End Sub

以下のように、受ける「var」をバリアント型(Variant)で定義することで受け取れますので、「バリアント型の配列」でなくても大丈夫です
Sub FuncForEachNextOK()
Dim var As Variant
Dim str(3) As String
Dim i As Integer
For i = 0 To 3
str(i) = Trim(i)
Next i
For Each var In str
Debug.Print Trim(var)
Next
End Sub
ちなみに、FileSystemObjectのFileオブジェクトを格納したCollectionから、Fileオブジェクトを取り出すにはどうするのか!?ですが・・こうします!
Sub FuncForEachNextCollection(data As Collection)
Dim fl As File
For Each fl In data
Debug.Print fl.Name
Next
End Sub
Collectionの中身がFileオブジェクトなので、受け側の変数には、バリアント型 の変数、汎用オブジェクト変数や特定のオブジェクト変数が指定できるのです
・While…Wend ステートメント
繰り返しは色々あるのですが、このステートメントは正直言って、あまり使いませんw
なので、使い方は、どこぞのサンプルをほぼほぼそのまんま載せますw(怒られる?)
Sub FuncWhileWend()
Dim Counter
Counter = 0
While Counter < 5
Counter = Counter + 1
Debug.Print Counter
Wend
Debug.Print Counter
End Sub
Counterが5未満の間、+1の処理を繰り返すので、実行結果は・・ご想像にお任せしますw
必ず指定回数を繰り返すので、途中で抜けるには強制的に「Exit Sub」とかすることになるので、あまりよろしくないです
サンプルも悪いので、回数がわかっているなら、ForNextステートメントでいいですし、カウンターが必要ならなおさらForNextステートメントでしょ!?
って、なってしまいますが、もう少し複雑な条件の間に処理を行わせるとか、もしくは複雑な条件でカウントアップするような場合には、使えるんでしょうけどね・・
きっと次に紹介するステートメントで、より柔軟にできちゃうんですw
・Do…Loop ステートメント
条件を満たすまで、処理を繰り返すことができますし、1つのステートメントですが、条件の設定が「Do」の後と「Loop」の後の2か所で設定できるので、構文が2つあるのです!
Sub FuncDoLoop()
Dim idx As Integer
idx = 0
Debug.Print "①"
Do While (idx < 3)
idx = idx + 1
Debug.Print "idx = " & idx
Loop
Debug.Print "②"
Do
idx = idx + 1
Debug.Print "idx = " & idx
Loop While (idx < 6)
Debug.Print "③"
Do
idx = idx + 1
Debug.Print "idx = " & idx
Loop Until (idx >= 9)
Debug.Print "④"
Do Until (idx >= 12)
idx = idx + 1
Debug.Print "idx = " & idx
Loop
Debug.Print "⑤"
Do While (idx < 12)
idx = idx + 1
Debug.Print "idx = " & idx
Loop
Debug.Print "⑥"
Do
idx = idx + 1
Debug.Print "idx = " & idx
Loop While (idx < 12)
Debug.Print "⑦"
Do
If idx > 15 Then Exit Do
idx = idx + 1
Debug.Print "idx = " & idx
Loop While (idx > 12)
End Sub
長くなってしまいましたw
構文的には、これと・・
Do [{ While | Until } condition ]
[ statements ]
[ Exit Do ]
[ statements ]
Loop
これ・・・
Do
[ statements ]
[ Exit Do ]
[ statements ]
Loop [{ While | Until } condition ]
ちなみに、上のサンプルの結果はこうなりますが、やりたいことが伝わりますかね?w
①
idx = 1
idx = 2
idx = 3
②
idx = 4
idx = 5
idx = 6
③
idx = 7
idx = 8
idx = 9
④
idx = 10
idx = 11
idx = 12
⑤
⑥
idx = 13
⑦
idx = 14
idx = 15
idx = 16
「Do」か「Loop」のどちらに条件を書くかによって、当然ですが処理が異なり、①~④は単純に構文のパターンを網羅しただけです
- ①:idxが3未満の間、繰り返す
- ②:idxが6未満の間、繰り返す
- ③:idxが9以上になるまで、繰り返す
- ④:idxが12以上になるまで、繰り返す
⑤~⑥は同じ条件式でも評価されるタイミングが異なるため、ステートメントが実行されるかどうかが異なることを示しています
- ⑤:idxが12なので、ステートメント実行前に評価され、実行されない
- ⑥:idxが12ですが、ステートメント実行後に評価され、実行される
⑦は「Exit Do」で任意にステートメントを終了する(抜ける)ことができることを示しています
■まとめ
そろそろ頭が痛くなる人もいるかと思いますが、これでほぼ肝心なことは全て記載したと思います!
変数と関数、代入、分岐と繰り返しは説明したので、あとは入出力の方法だけなのですが、それは多種多様なので、今後どこかのプログラム作成中に出てくるので、気付いてくださいw
■次回
次回こそファイル一覧の続きをやります!
ではでは