皆さまこんにちは!
このサイトの管理者のHide(ヒデ)と申します。
前回のブログでは、Do While文とは何かという点についてお伝えした後、実際にプログラムを作成して動かしてみました。
今回は、「Do While文の処理を途中で中断する方法」と「Do While文内の処理をスキップしてDo While文の処理を先に進める方法」についてお伝えしたいと思っていますが、実はこのお話は下記のFor文のブログでお伝えした方法と内容がほぼ一緒となりますので、本ブログでは、For文との違いのみにポイントを絞ってお伝えしていきたいと思います。
下記のブログをまだお読みでない方は、先に下記のブログをお読み頂いてから本ブログをお読み頂ければ幸いです。
For文の動きをコントロールする方法について解説したブログはこちら
Contents
1. Do While文の処理を途中で中止する方法
Do While文はループ変数が終了値になる前に途中で中止し、次のプログラムのステップに進めることが可能です。この方法についてお伝えします。これには2つの方法があります。
1-1. Exit Do 文を使って中止する
まず、「Exit Do」という文を使ってDo While文の処理を途中で中止することができます。まずは、簡単なプログラムを考えてみましたのでご覧ください。プログラムの名前はDoCalcSumとしました。
Sub DoCalcSum()
'変数の宣言
Dim Sum As Long
Dim i As Long
'明示的な変数の初期化
Sum=0
'ループ変数の初期化
i=StartNum
'整数の和の計算
Do While i<=EndNum
If i=StartNum+3 Then
Exit Do
End If
Sum=Sum+i
i=i+1
Loop
'整数の和の結果を表示
Debug.Print MsgStr & Sum
End Sub
上記のDoCalcSumというプログラムはFor文のブログで取り上げたCalcSum3というプログラムをFor文からDo While文を利用する形に書き換えたものです。
ここで補足になりますが、StartNum,EndNum,MsgStrの部分はFor文のブログと同様に定数で、それぞれ「1」,「100」,「整数の和=」という値が入っているものとします。またFor文の時と異なり、ループ変数iの初期化や更新の行を別途記述している点にご注意ください。
このプログラムのポイントとなる部分は下記のIf文になります。
If i=StartNum+3 Then
Exit Do
End If
このIf文の意味ですが、ループ変数iの値がStartNum+3、つまり(1+3になるので)4と同じ値になったらDo While文の処理を終了して、次に実行されるプログラムの行に進みなさいという意味です。このIf文により、本来なら1~100までの整数の和を計算するところを途中で中止することになります。
では、Do While文の次に実行されるプログラムの行とはどこのことでしょうか?
それは「Debug.Print MsgStr & Sum」という、整数の和の結果を表示する命令の行です。
Exit Do 文の命令による「Do While文の中止と次に実行されるプログラムの行への移動」のイメージは下図の赤矢印のようになります。このようにExit Do文には現在実行中のDo While~Loopのくくりから外へ(次のプログラムのステップへ)ジャンプする機能があります。またDo While~Loopに囲まれた間でのみ利用できる点にご注意ください。
1-2. GoTo 文を使って中止する
次に実行中のDo While文をGoTo文を使って中止する方法をお伝えしたいと思います。まず、プログラムからご覧ください。
Sub DoTimesTable()
'変数の宣言
Dim i As Long
Dim j As Long
'ループ変数iの初期化
i=1
'九九の計算
Do While i<=9
'ループ変数jの初期化
j=1
Do While j<=9
Debug.Print i & “*” & j & “=” & i*j
If (i=1) And (j=3) Then
GoTo Label
End If
j=j+1
Loop
i=i+1
Loop
Label:
Debug.Print “プログラムの終了直前です。”
End Sub
このプログラムはFor文のブログでお伝えした九九の計算のプログラムTimesTable2を、For文からDo While文を利用する形に書き換えたものです。TimesTable2のプログラムと動きは同じで、九九の掛け算を全て行うのではなく「1の段を3つまで計算したら終了する」プログラムになっています。For文の時と異なり、ループ変数iとjの初期化や更新の行を別途記述している点にご注意ください。
このプログラムのポイントとなる部分は下記の2点になります。
【ポイントその1】
If (i = 1) And (j = 3) Then
GoTo Label
End If
このIf文の意味ですが「 変数iが1と等しく なおかつ 変数jが3と等しい 」場合、Label と書かれた行へジャンプしなさいという意味になります。このIf文がまさに「1の段を3つまで計算したら終了する」処理になります。
【ポイントその2】
Label:
Debug.Print "プログラムの終了直前です。"
この部分は、GoTo文のジャンプ先になります。「Label:」という行がGoTo文の行からのジャンプ先を表しています。但し、「Label:」の行はプログラムの命令ではないため、実際のジャンプ先はその次の行の命令である「Debug.Print」から始まる行になります。
GoTo 文の命令による「Do While文の中止と次に実行されるプログラムの行への移動」のイメージは下図の赤矢印のようになります。このようにGoTo 文には現在実行中のプログラムの行からラベル名で指定された行(実際には「ラベル名:」と書かれた行の次の行以降に来る最初のプログラムの命令の行へ)ジャンプする機能があります。
1-3. Exit Do 文についての要注意事項
先ほど「九九の計算を1の段の3つまで計算したら終了する」プログラムの例を見て頂きました。このプログラムでDo While文を中止するためにGoTo文を使いましたが、この部分を単純にExit Do文に書き換えても同じように動くかといういうと実はそうではないんです。(これはFor文におけるExit Forと同じです。)
九九の計算はDo While文を入れ子にした2重ループという構造になっているのですが、Exit Do文は、あくまで現在実行中のDo While文の1段外に出るという機能しかもっていないんですね。この点についてわかりにくいかもしれませんので下図のイメージ図をご覧ください。
上図は先ほどの九九の計算のプログラムのGoTo文をExit Do文に書き換えて抜粋したものです。また見やすいようにプログラムについて空白行を追加しプログラムの行間隔を少し開けました。
赤矢印の部分がExit Do文によってジャンプする先を表しています。本当は2重ループになっているDo While文の処理を全て中止して、プログラムの終了する方向へ向かいたいところですが、このプログラムは、外側のi=i+1 の行へプログラムが進んでしまいます。
その結果、九九の計算を1の段の3つ計算した後、2の段から9の段まで計算して終了するという動きになってしまいます。
このようにExit Do文は現在のDo While文の1つ外側にジャンプする動きしかしないので、今回のような2重ループでは、GoTo文を利用して一気に2つのDo While文の外側にジャンプする方法が簡単です。
もしExit Do文を使いたい場合は、内側のDo While文の中のIf文でGoTo文の行をExit Doに変えた後、さらに内側のLoop文の直後にIf文を入れて条件判定を行う必要があります。またその際、GoTo文には必須であったジャンプ先のラベル記述や設置は不要となります。参考までにそのプログラムを下記に掲載しました。プログラムの名前はDoTimesTable2としました。
Sub DoTimesTable2()
'変数の宣言
Dim i As Long
Dim j As Long
'ループ変数iの初期化
i = 1
'九九の計算
Do While i <= 9
'ループ変数jの初期化
j = 1
Do While j <= 9
Debug.Print i & "*" & j & "=" & i * j
If (i = 1) And (j = 3) Then
Exit Do
End If
j = j + 1
Loop
If (i = 1) And (j = 3) Then
Exit Do
End If
i = i + 1
Loop
Debug.Print "プログラムの終了直前です。"
End Sub
いかがでしょうか。Exit Do文を使うとIf文による条件判定が2回必要となりますので、先ほどのGoTo文を使ったプログラムの方がすっきりして見やすいですね。
ここまで、Exit Do文の注意点についてお伝えしました。
2. Do While文内の処理をスキップしてDo While文の処理を先に進める方法
先ほどまでは、Do While文を途中で中止してプログラムを終了する方向に向かうプログラムの記述方法をお伝えしましたが、ここでは、Do WhileとLoopの間にはさまれた「プログラムの命令」をスキップしてDo While文のループ処理を早める方法をお伝えします。Do While文は命令を繰り返す文なのでループ処理という言い方もしますので覚えておいてください。
まずは、プログラムからご紹介しますね。下記のプログラムは1~100までの奇数の和を計算するプログラムです。プログラムの名前はDoCalcSum2としました。このプログラムはFor文のブログでご説明したCalcSum4のプログラムをFor文を利用する形からDo While文を利用する形に書き換えたものです。
Sub DoCalcSum2()
'変数の宣言
Dim Sum As Long
Dim i As Long
'明示的な変数の初期化
Sum=0
'ループ変数の初期化
i=1
'奇数の和の計算
Do While i<=100
if (i Mod 2)=0 Then
GoTo SkipLabel
End If
Sum=Sum+i
SkipLabel:
i=i+1
Loop
'奇数の和の結果を表示
Debug.Print "奇数の和=" & Sum
End Sub
このプログラムのポイントとなる部分は下記の点になります。
if (i Mod 2)=0 Then
GoTo SkipLabel
End If
このIf文でModという用語が出てきました。このModは割り算の余りを求めるもので下記のように記述することで、余りを求めることが可能です。
「割られる数」Mod「割る数」
つまりこのIf文の意味は「変数iを2で割った余りが0だったら」という意味で、この条件に一致したら「GoTo SkipLabel」の命令を実行することになります。
このGoTo文にはSkipLabelというラベル名が書かれていますので、もしIf文の条件に一致し「GoTo SkipLabel」行の命令が実行された場合には、DoCalcSum2のプログラムの「SkipLabel:」と書かれた行(実際にはこの「SkipLabel:」の次の行以降に来る最初のプログラムの命令の行)にプログラムの処理がジャンプします。
「SkipLabel:」の次の行以降に来る最初の命令は、今回のプログラムでは「i=i+1」の命令になりますね。つまり、GoTo文により「Sum=Sum+i」の行の「和の計算」は行われずにスキップして、計算に利用する変数iの内容を次の数に進めるということを行っているのです。
この一連の動きにより、ループ変数iが偶数の場合は和の計算を行わずにスキップして、最終的に奇数だけの和の計算が行われるという動きになるのです。このプログラムの仕組みについて何となく見えてきましたでしょうか?
「Do While文内の処理をスキップしてDo While文の処理を先に進める方法」のイメージは下図の赤矢印のようになります。
このような流れで、これ以降もループ変数iが偶数の場合は和の計算をスキップしながら計算が行われていきます。
DoCalcSum2のプログラムを実行すると、下図のようにイミディエイトウィンドウに「奇数の和=2500」というメッセージが表示されます。
ここまでで、「Do While文内の処理をスキップしてDo While文の処理を先に進める方法」について見てきました。このようにExcel-VBAではGoTo文とラベル名のセットでこの処理を実現しますが、他のプログラミング言語ではラベル名などは不要でGoTo文の行の部分に「continue;」と書くことだけで実現できるものもあります。
3. まとめ
長くなりましたが、今回はDo While文の動きを色々コントロールする方法について見てきました。
おつかれまでした!
【電子書籍出版のご案内】
本ブログで扱っている「Excel VBA 入門」の内容が、内容を大幅に増やした形で電子書籍(Kindle)になりました。ご興味のある方は、ぜひご覧頂ければ幸いに存じます。
Excel VBA に挫折しないためのプログラミング超入門 (基礎から応用まで)