このページの内容について
このページは、VBAエキスパート(ExcelVBAベーシック)試験合格講座の第十一回記事です。前回に引き続き公式テキスト第7章「ステートメント」の内容について解説します。1時間の講義でお話する程度の分量です。講座受講者の復習での利用を想定しています。
プログラムの基本構成(分岐処理)
プログラムは3つの処理から成り立っています。ひとつは以前に説明した「順次処理」で、もうひとつは前回解説をした「繰り返し処理」です。最後の処理は「分岐処理」です。プログラムが「定型的なルールに従った処理」が得意だといわれるのはこの処理を簡単に実現することができるためです。VBAには分岐処理の方法が2つあります。
Ifステートメント
条件がTrueの時とFlaseの時とで別の処理を実行する
Ifによる条件分岐はいくつかの書き方がありますが、基本は条件が「True」の時と「False」の時で別の処理が実行されるという構造です。
書式1
If 条件 Then 処理
書式1の記載方法だと、処理は1行しか記述できません。条件が「True」となる時のみ処理が実行され「False」の場合の処理はありません。
サンプルコード(クリックでコピー)
Private Sub Test_If_1()
Dim rng As Range
Set rng = ThisWorkbook.Worksheets(1).Range("A1") '①
rng.Value = "テスト" '②
If rng.Value = "テスト" Then Call MsgBox("入力に成功しました", vbInformation) '③
End Sub
処理の詳細
①変数「rng」にこのブックの1番目のシートのセル「A1」オブジェクトを格納する
②セル「A1」に値「テスト」を入力する
③rng.Value と 値「テスト」が等しいときに、メッセージを表示する
実行結果
上記のサンプルを実行すると、まずセル「A1」に値「テスト」を入力します。その後、Ifの条件は常に「True」となり、メッセージを表示ます。
書式2
If 条件 Then
処理
End If
書式2の記載方法は、書式1と同様、条件が「True」となる時のみ処理が実行され「False」の場合の処理はありません。書式1と異なるのは処理を複数行にわたって記述できることです。
サンプルコード(クリックでコピー)
Private Sub Test_If_2()
Dim rng As Range
Set rng = ThisWorkbook.Worksheets(1).Range("A1") '①
rng.Value = "テスト" '②
If rng.Value = "テスト" Then '③
Call MsgBox("入力に成功しました", vbInformation) '④
rng.Value = "メッセージ出力完了" '⑤
End If '⑥
End Sub
処理の詳細
①変数「rng」にこのブックの1番目のシートのセル「A1」オブジェクトを格納する
②セル「A1」に値「テスト」を入力する
③rng.Value と 値「テスト」が等しいときに、④以下の処理を実行する
④「入力に成功しました」というメッセージを表示する
⑤セル「A1」に値「メッセージ出力完了」を入力する
⑥If分岐の終端
実行結果
上記のサンプルを実行すると、まずセル「A1」に値「テスト」を入力します。その後、Ifの条件は常に「True」となり、メッセージを表示し、セル「A1」に値「メッセージ出力完了」を入力します。
書式3
IF 条件 Then
処理(Trueパート)
Else
処理(Falseパート)
End IF
この書式では、条件が「True」の時と「False」の時で実行する内容が異なります。処理は複数行記述することができます。
サンプルコード(クリックでコピー)
Private Sub Test_If_3()
Call VBA.Randomize '①
If VBA.Rnd >= 0.5 Then '②
Debug.Print "アタリ!" '③
Else '④
Debug.Print "ハズレ・・" '⑤
End If '⑥
End Sub
処理の詳細
①乱数の初期化する
②生成された乱数が0.5以上の時に③、0.5未満の時に④以下の処理を実行する
③「アタリ!」という文字列をイミディエイトウィンドウに出力する
④Trueパートの終端
⑤「ハズレ・・」という文字列をイミディエイトウィンドウに出力する
⑥If分岐の終端
実行結果
上記のサンプルを実行すると、50%の確率で「アタリ!」とメッセージが表示されます(たぶん)。
書式4
IF 条件 Then
処理(Trueパート1)
ElseIf 条件 Then
処理(Trueパート2)
Else
処理(Falseパート)
End IF
Ifによる分岐処理は「True」か「False」の2パターンしか表現できませんが、重ねて書くことで複数分岐を実現することもできます。ただし公式テキストでも「推奨しません」と記載されているように、スタンダードで学習する「Select Caseステートメント」でより簡単に実現できるためあまり使用する機会はありません。
サンプルコード(クリックでコピー)
Private Sub Test_If_4()
Dim lot As Double
Call VBA.Randomize '①
lot = VBA.Rnd '②
If lot < 0.1 Then '③
Debug.Print "大アタリ!" '④
ElseIf lot < 0.4 Then '⑤
Debug.Print "アタリ!" '⑥
Else '⑦
Debug.Print "ハズレ・・" '⑧
End If '⑨
End Sub
処理の詳細
①乱数の初期化する
②ランダム生成した数値を変数「lot」に格納する
③変数「lot」が0.1未満の時に④以下を実行する
④「大アタリ!」という文字列をイミディエイトウィンドウに出力する
⑤変数「lot」が0.4未満の時に⑥以下を実行する
⑥「アタリ!」という文字列をイミディエイトウィンドウに出力する
⑦Trueパートの終端、これまでの条件がすべて「False」の場合に⑧以下を実行する
⑧「ハズレ・・」という文字列をイミディエイトウィンドウに出力する
⑨If分岐の終端
実行結果
書式3のサンプルから、ランダムに生成された値のアタリ判定の分布を変更しています。
0.1未満 ・・・ 大アタリ
0.4未満 ・・・ アタリ
それ以外 ・・・ ハズレ
いろいろな分岐処理
And(AかつB)
And演算子は左右がいずれも「True」である場合は「True」、一方でも「Flase」だった場合は「False」を返す演算子です。日本語では「〇〇 かつ 〇〇」と表現されます。And演算子をIfの条件に指定することで複数の条件で分岐判定をさせることができます。
ユーザーから数値の入力を受け付ける
ユーザーから数値の入力を受け付ける場合、そもそもユーザーは数値を入力をするのか、こちらの意図した範囲で入力をするのか、などを考える必要があります。ここではIf分岐処理を使ってユーザーが意図しない入力をした場合に、処理を分岐させるコードを記述してみます。
サンプルコード(クリックでコピー)
Private Sub Test_If_And()
Dim input_val As String
'①
input_val = VBA.InputBox("0より大きい数字を入力してください", "数値入力受付")
If VBA.IsNumeric(input_val) And input_val > 0 Then '②
Debug.Print "正しく入力されました" '③
Else '④
Debug.Print "正しく入力されませんでした" '⑤
End If '⑥
End Sub
処理の詳細
①変数「input_val」にユーザーが入力した文字列を格納する
②変数「input_val」が数値かつ0より大きい場合、③以下を実行する
③「正しく入力されました」という文字列をイミディエイトウィンドウに出力する
④Trueパートの終端
⑤「正しく入力されませんでした」という文字列をイミディエイトウィンドウに出力する
⑥If分岐の終端
実行結果
上記サンプルを実行すると入力受付画面が立ち上がります。指示通り0より大きい数値を入力すると「正しく入力されました」という文字列がイミディエイトウィンドウに出力されます。0や0より小さい値を入力すると「正しく入力されませんでした」と出力します。しかし入力をしなかったり、数値ではない値を入力した場合は、エラーが発生します。
VBAではAnd演算子は短絡しない
And演算子の性質として、左項の値が「False」の場合、右項の値がなんであれ結果は「False」となります。このことから多くのプログラミング言語では左項の結果が「False」の場合、右項の条件判定を実行しません(処理の短絡)。しかし、VBAでは結果が明らかな場合でも両方の判定を実行します。そのため、上記サンプルで数値以外の値を入力した場合、IsNumericの結果が「False」となるにも関わらず、続く「0」との比較を実行します。そのため文字列と数値を比較しようしてエラー(型エラー)が発生します。
ユーザーから数値の入力を受け付ける(入れ子版)
繰り返し処理の時と同様に、分岐処理も入れ子構造にすることができます。先ほどの数値の入力を受け付けるサンプルを入れ子構造で記述し直してみます。
サンプルコード(クリックでコピー)
PPrivate Sub Test_If_And_2()
Dim input_val As String
'①
input_val = VBA.InputBox("0より大きい数字を入力してください", "数値入力受付")
If VBA.IsNumeric(input_val) Then '②
If input_val > 0 Then '③
Debug.Print "正しく入力されました" '④
Else '⑤
Debug.Print "0以下の値が入力されました" '⑥
End If '⑦
Else '⑧
Debug.Print "数値が入力されませんでした" '⑨
End If '⑩
End Sub
処理の詳細
①変数「input_val」にユーザーが入力した文字列を格納する
②変数「input_val」が数値である場合、③以下を実行する
③変数「input_val」が0より大きい場合、④以下を実行する
④「正しく入力されました」という文字列をイミディエイトウィンドウに出力する
⑤③のTrueパートの終端
⑥「0以下の値が入力されました」という文字列をイミディエイトウィンドウに出力する
⑦③のIf分岐の終端
⑧②のTrueパートの終端
⑨「数値が入力されませんでした」という文字列をイミディエイトウィンドウに出力する
⑩②のIf分岐の終端
実行結果
上記サンプルでは数値ではない値を入力した場合も、エラーは発生せず「数値が入力されませんでした」という文字列がイミディエイトウィンドウに出力されます。入れ子構造にすることで、数値以外の値が入力された場合もエラーを発生させずに処理をすることができました。このようにAndを使うよりもIfを入れ子で記述する方が意図した結果となる場合もあります。
OR(AまたはB)
ORは左右いずれかが「True」である場合は「True」、いずれも「Flase」だった場合は「False」を返す演算子です。日本語では「〇〇 または 〇〇」と表現されます。
世界のナベアツ(桂三度)さんのギャグをマクロで表現する
ご存じない方のために説明すると「3の倍数と3が付く数字の時だけアホになります」というギャグをマクロにします。
サンプルコード(クリックでコピー)
Private Sub WriteNabeatsuNumber()
Dim ws As Worksheet
Dim r As Long
Set ws = ThisWorkbook.Worksheets(1) '①
For r = 1 To 100 Step 1 '②
ws.Cells(r, 1).Value = r '③
If r Mod 3 = 0 Or VBA.InStr(r, 3) > 0 Then '④
ws.Cells(r, 1).Font.Name = "Algerian" '⑤
ws.Cells(r, 1).Font.Size = 33 '⑥
Else '⑦
ws.Cells(r, 1).Font.Name = "Meiryo UI" '⑧
ws.Cells(r, 1).Font.Size = 11 '⑨
End If '⑩
Next r '⑪
End Sub
処理の詳細
①変数「ws」にこのブックの1番目のシートのオブジェクトを格納する
②カウンタ変数「r」を1ずつ増やしながら1から100の間、繰り返す
③r行目・1列目に変数「r」に格納されている数値を入力する
④変数「r」を3で割った余りが「0」の場合、または、変数「r」に「3」が含まれる場合は、⑤以下の処理を実行、それ以外の場合は、⑧以下の処理を実行する
⑤フォント「Algerian」を設定する
⑥フォントサイズを「33」に設定する
⑦Trueパートの終端
⑧フォント「Meiryo UI」を設定する
⑨フォントサイズを「11」に設定する
⑩If分岐の終端
⑪繰り返し処理の終端、③に戻る
実行結果
上記サンプルを実行するとA列に1から100までの数値が入力され「3の倍数と3が付く数字の時だけフォントと文字サイズを変化させます。
Comment