和風スパゲティのレシピ

日本語でコーディングするExcelVBA

Do While と Do Until の違い

繰り返し処理(ループ)を行うためのステートメントである、
Do While~Loop文と、Do Until~Loop文の違いを解説します。

同じところ

どちらも繰り返し処理(ループ処理)を行うためのステートメントです。

For文が回数で繰り返しをコントロールするのに対し、
両者とも条件式によってループを続けるかを判定します。

違うところ

「条件を満たす間続ける」のがDo While文
「条件を満たしたら終わる」のがDo Until文です。

例えばA1セルからA10セルを処理する場合は、

R = 1
Do While R <= 10
    Cells(R, 1) = ○○
    R = R + 1
Loop

R = 1
Do Until R > 10
    Cells(R, 1) = ○○
    R = R + 1
Loop

この2つのコードは全く同じ動きをします。

  • Rが10以下の間は続ける
  • Rが10を超えたら終わる

は同じ意味ですからね。


ということで、WhileとUntilは完全な反転関係にあり、

Do While R <= 10

Do Until Not(R <= 10)

と、WhileをUntil Notに機械的に書き換えることができます。


While文は「条件式がTrueの間続ける」、
Until文は「条件式がTrueになるまで=Falseの間続ける」なので、
Notでぴったり反転するのは、当たり前といえば当たり前ですね。

使い分け

ぶっちゃけどっちも使わなくていい気がします。

というのも、今回のA1セルからA10セルを処理する場合は、

' For文を使用
For R = 1 To 10
    Cells(R, 1) = ○○
Next

' Do~Loop文を使用
R = 1
Do
    Cells(R, 1) = ○○
    
    R = R + 1

    If R = 10 Then Exit Do
Loop

このようにFor~Next文と、Do~Loop文で書くことができます。


この二つはどちらも長所があり、
まずFor文は、「簡単なループ処理なら短く簡潔」に書けます。

今回の「A1セルからA10セル」のような単純な処理の場合は、
間違いなくFor文が一番見やすいですね。


対してDo~Loop文は、「判定やカウンタのタイミングが自由自在でなんでもできる」というのが長所です。

ちょっと変ですが、

R = 0
Do
    R = R + 1

    If R = 11 Then Exit Do
    
    Cells(R, 1) = ○○

Loop

こう書いても同じ動きをします。
 

  • いつカウンタを進めるか
  • いくつカウンタを進めるか
  • カウンタがないとき、終了フラグなどをどう処理するか
  • いつ終了判定をするか
  • 終了時の最終処理を行うか

を自由に決めることができるので、
複雑なループ処理を書くにはDo~Loop文を使います。


この点、Do While/Untilって中途半端なんですよね。

For文ほど読みやすく簡潔には書けませんし、
その割にはDo~Loop文ほど自由がききません。


このDo~Loop文の自在さで、Do While/Until文は完全に再現することができ、

Do While R <= 10
' ↓ 書き換え
Do
    If (R < = 10) = False Then Exit Do
Do Until R > 10
' ↓ 書き換え
Do
    If R > 10 Then Exit Do

という対応になります。


ほんのちょっとコードは長いですが、ループ処理に慣れていない方にとっては、
書き換えた方が断然わかりやすいですよね。

Do~Loopで繰り返し、If~Exit Doで抜けるのがはっきり明示されている方が、
かなり理解しやすいのではないでしょうか。


特に「Do While/Untilの判定は各ループの開始時」という仕様が明確でないのが、
学び始めに理解を妨げる原因になっているような気がします。


逆に言えば、Do While/Until文は、
「Doの直後にIf ~ Exit Doを書く場合は、While/Untilでそれを省略できますよ」
という、ただ短く書くためだけのステートメントとも言えます。

そして、ただ短く書くだけならForさんが最強ですからね。


続行/離脱の条件が1ヵ所にしか書けず、しかも判定タイミングも開始時に固定なため、

  • Do~Loop文なら書けるけど、Do While~Loop文だと難しい
  • Do While文で書けるような処理なら、For文で書いた方が読みやすい

という状況に陥りやすいです。


既存のマクロを読むために必要なので、存在を知っておく意味はあると思いますが、
別段使わなくてもいいような、そんな気のするステートメント達ですね。

使いどころ

全体的な話をするといらない子扱いしてしまいましたが、
ピンポイントで向いている処理というのはあります。

例えば「フォルダ内のすべてのファイルを処理」するときに、

Dim 処理ファイル名 As String
処理ファイル名 = Dir("○○フォルダ\売上データ(*).xlsx")

Do While 処理ファイル名 <> ""

    Workbooks.Open ("○○フォルダ\" & 処理ファイル名)


    ~開いたブックへの処理~


    処理ファイル名 = Dir()
Loop

と書くことができます。


「ファイルがなくなると""を返すDirの性質」を、

Do While Dirの結果 <> ""

と書くことで、
「Dir関数がファイル名を返している間はループを続ける」
というのを表現しています。

こういう定型化されたコードではたまに出てきますので、
読むためにも知っておく必要はあるでしょう。


ただ、じゃあこれをDo~Loop文で書くとどうかというと…

Dim 処理ファイル名 As String
処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx")

Do

    Workbooks.Open ("処理フォルダ\" & 処理ファイル名)


    ~開いたブックへの処理~


    処理ファイル名 = Dir()

    If 処理ファイル名 = "" Then Exit Do

Loop

うーん、やっぱりこっちがわかりやすいですね(笑)

慣れてる方には、ちょっと冗長なのでしょうけど。


なぜDo~Loop文が分かりやすいのかというと、

  1. 最初のファイルを取得
  2. そのファイルを開いて処理
  3. 次のファイルを探す
  4. あればLoop、無ければExit

のように、その自由度を活かして時系列順に書くことができるからです。


Do While/Untilはループの開始時に条件を書くしかなく、判定もそこでしかできないので、慣れないうちは処理の流れをイメージしづらいのです。


Do While文と、Do Until文が、

  • For文ほど読みやすく簡潔に書けません。
  • その割にはDo~Loop文ほど自由がききません。

と感じる理由はなんとなく伝わったでしょうか。


ループ処理に慣れていない方は、
Do~Loop文の中で、丁寧にIf~Exit Doを書いた方が読みやすいと思います。

Do Whileをスラスラ読めるレベルの方も、たった十数文字程度の差なら、
のちに引き継ぐかもしれない後輩のためにも、
Do~Loop文で書いてあげることをおすすめします。

おまけ:初めから条件を満たさない場合

補足になりますが、Do While/Until文は、

「最初から条件を満たしていない場合は、ループに入らない」

という特徴があります。


先ほどの「フォルダ内のファイルをループ」について、

Dim 処理ファイル名 As String
処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx")

この時点でファイルがなく、Dirが最初から""を返した場合に、

Do While 処理ファイル名 <> ""
    Workbooks.Open ("処理フォルダ\" & 処理ファイル名)
    ' ↑実行されないためエラーは出ない
Do
    Workbooks.Open ("処理フォルダ\" & 処理ファイル名)
    ' ↑実行されてしまい、エラーになる

という違いがあります。


ただ、これを利点と言っていいかは正直疑問で、個人的には、
通過するのに一度も処理されないループブロックは書くべきではない
と思っています。

今回の場合は、

Dim 処理ファイル名 As String
処理ファイル名 = Dir("保存フォルダ\売上データ*.xlsx")

If 処理ファイル名 = "" Then
    MsgBox("処理対象のファイルがひとつもありませんでした。")
    Exit Sub
End If

Do
    Workbooks.Open ("処理フォルダ\" & 処理ファイル名)

    ~~

と書いた方が絶対に読みやすいですよね?


「ループの繰り返し条件をスタートから満たしていない」というのはかなり大事な例外でしょうから、キッチリIf文で分けて準備段階で処理し、必要ならそこでExitするべきです。


片づけられるものはしっかり片付けてから、
本題に集中できるメインコードを書くよう心がけましょう。