条件を満たすまで繰り返し(ループ)処理を行う方法を解説します。
Do Until ~ Loopステートメント(Do Until文)を使用します。
基本構文
Do Until 終了条件 ' ここに繰り返したい処理 Loop
サンプルコード
' A列に空セルが登場するまで繰り返し Dim ws処理シート As Worksheet Set ws処理シート = ThisWorkbook.Worksheets("○○") Dim R As Long: R = 2 Do Until ws処理シート.Cells(R, 1).Value = "" ' 処理例:C列=A列×B列 ws処理シート.Cells(R, 3).Value = _ ws処理シート.Cells(R, 1).Value * ws処理シート.Cells(R, 2).Value R = R + 1 Loop
' フォルダ内のExcelファイルを順番に処理 Dim フォルダパス As String フォルダパス = "C:\○○" Dim dirファイル名 As String dirファイル名 = Dir(フォルダパス & "\*.xlsx") Do Until dirファイル名 = "" Dim ファイルパス As String ファイルパス = フォルダパス & "\" & dirファイル名 ' 対象ファイルへの処理 Dim wb処理ブック As WorkBook Set wb処理ブック = Workbooks.Open ファイルパス ' 次のファイルを取得 dirファイル名 = Dir() Loop
解説
条件を満たすまで繰り返し処理を行うには、
Do Until Loopステートメントを使用します。
Do Untilの条件式がFalseの間は処理を繰り返し、
条件式がTrueになるとループを終了します。
Do Until 終了条件 ' 終了条件がFalseの間だけ実行 Loop
ループへ入る前に条件式を判定するため、
最初から条件を満たしている場合は、ループ内の処理が一度も実行されません。
Do Until文にはループ用の変数を更新する機能はついていませんので、
次のループに入る直前にループ用の変数を更新する必要があります。
R = R + 1 Loop
' 次のファイルを取得 dirファイル名 = Dir() Loop
この更新を忘れると変数が更新されず無限ループになってしまいます。
For文と違い書く場所がループの最後尾になりますので、
忘れないように注意して使用しましょう。
途中でループを終了する - Exit Do
Do Until文の条件とは別の条件でループを途中終了したい場合は、
Exit Doステートメントを使用します。
Dim i As Long: i = 1 Do Until i = 10 Debug.Print i ' ← 1, 2, 3 でループを抜ける If i = 3 Then Exit Do i = i + 1 Loop
For文におけるExit Forは「規則的なループ内での例外終了」でよく使いますが、
Do Until文は元々終了条件を判定して動くループ文のため、
さらにExit Doを追加で使用する機会は少ないと思います。
複雑な終了条件判定が必要になったら使用してください。
他のループ構文(Do While / For)との違い
Do While文との違い
Do Until文と対になるステートメントとして、
Do While ~ Loopステートメントがあります。
こちらは「条件がTrueの間繰り返す」というループ処理になっており、
以下のコードは全く同じ動きになります。
' 空のセルを発見したらループを終了(Until) Dim R As Long: R = 2 Do Until ws処理シート.Cells(R, 1).Value = "" ' ここに各行への処理 R = R + 1 Loop
' セルが空でない間ループを続ける(While) Dim R As Long: R = 2 Do While ws処理シート.Cells(R, 1).Value <> "" ' ここに各行への処理 R = R + 1 Loop
Until/Whileのあとの「=」「<>」が反転しているだけで、
あとは全く同じコードですね。
システム・機能面ではどちらを使った方が良いという差はありませんので、
書きやすさ、読みやすさで使うステートメントを決めてください。
処理の内容をイメージしてみて、
「~~の間続ける」「~~になったら終わる」
このどちらが日本語としてしっくりくるかで選んでしまってOKです。
For文との違い
例えば「2行目から最終行まで」のように開始位置と終了位置があらかじめ決まっている処理は、For文とDo Until文のどちらで書くことも出来ます。
Dim R As Long: R = 2 Do Until R > 最終行 ' ここに行ごとの処理 R = R + 1 Loop
↕ 全く同じ処理
Dim R As Long For R = 2 To 最終行 ' ここに行ごとの処理 Next
上記のようにFor文とDo Until文で同じ処理を書くことが出来ますが、
使い分けとしては、基本はFor文を使っておく方が良いです。
Do Until文の方が複雑な条件を書くことが出来るため自由度が高いのですが、
自由度が高いからこそ、単純な処理がやや冗長になって読みにくくなります。
For文なら冒頭に「使う変数 / 初期値 / 最終値」がすべてそろっているのですが、
Do Until文だと
- 使う変数は上部で宣言されていて、初期値も自由に設定されている
- 終了条件はDo Until文冒頭に書かれている
- 変数の更新(ForでいうStep)はループ最後尾に書かれている
と、各所に散らばっていますからね。
For文に比べるとループの全体像をつかむのが少々難しくなる傾向があります。
- For文で書けるなら基本はFor文で書く
- For文で書けない条件判定が必要ならDo Until文で書く
という使い分けをするのがベストですので、
Do文の方が万能だからとむやみやたらに使いすぎないようにしておきましょう。
Do ~ Loop Until文との違い
「Until 終了条件」の記述は、実はLoopの後に書くこともできます。
Dim R As Long: R = 2 Do Until ws処理シート.Cells(R, 1).Value = "" ' ここに各行への処理 R = R + 1 Loop
↓ 書き換え
Dim R As Long: R = 2 Do ' ここに各行への処理 R = R + 1 Loop Until ws処理シート.Cells(R, 1).Value = ""
この二つはほとんど同じ動きをするのですが、
「条件を最初から満たしていても第1ループを実行するかどうか」
という点で大きな違いがあります。
上記の例だと、Loopの後にUntil条件を記載した場合は、
「A2セルがいきなり空セルでも第1ループだけは実行」されることになります。
正直言って「条件を満たしたとしても最低1回は実行」という場面は稀ですし、
実際にその場面に遭遇した際、それをLoop Untilで表現はすべきでないと思います。
「仕様を正確に知った上で、その仕様が利用された意図をつかむ必要がある」
というのは読みづらいコードの典型ですからね。
こういった複雑な処理を実装するなら最初から無限ループDo文を使って、
Dim R As Long: R = 2 Do ' 第1行以外で空セルを発見したらExit If ws処理シート.Cells(R, 1).Value = "" And R > 2 Then Exit Do End If ' ここに各行への処理 R = R + 1 Loop
こう書いた方が確実に意図は伝わるし読みやすいです。
Loopにも条件が書けるということは知っておきつつ、
よほどのことがない限りは使用を控えておきましょう。