VBAのループ処理 ForとDoの違いと使い分け
今回はプログラミングで通る道のひとつ、VBAのループ処理を解説します
Excelの作業では「1行ずつ順番に」「一番下の行になるまで」のように、同じ処理を繰り返したい場面がとても多いです
この記事では、VBAのループ処理を3つの系統に分けて、初心者の方にも分かりやすくまとめました
VBAのループ処理とは?3つの系統で全体像をつかむ
VBAのループ処理とは、ある条件の間や条件を満たすまで、同じ処理を繰り返す仕組みのことです
セルA1からA10までの値を順番に読み取る、リストの中から条件に合うデータだけ抜き出す、といった作業で活躍します
VBAのループ構文はいくつかありますが、ざっくり3系統に分けると全体像がつかみやすいです
まずはこの3つの違いをイメージしてもらえると、この先の話がすっと入ってきます
- For Next … 繰り返す回数が決まっているときの基本形
- For Each … セル範囲やコレクションなど集まりを丸ごと処理する
- Do Loop … 回数が読めず、条件しだいで繰り返したいとき
ジャベ雄迷ったら「回数が決まってる?」をまず考えるといいですよ
この記事で分かること
- 3系統それぞれの正しい書き方
- For・Do・Exit の違いと使い分け
- 無限ループの止め方と防ぎ方
- 重いループを速くするコツ
なお、ループのカウンターには変数を使います
変数や型がまだあやふやな方は、先にVBAの変数と定数の解説記事に目を通しておくと、この先がぐっと読みやすくなります
For Next:回数が決まった繰り返し
For Next は、指定した回数だけ繰り返す基本のループです
他の言語でもよく使う形なので、ここを押さえておくと応用が効きます
VBAでは次の形で書きます
※[]の中は省略できる部分です
For counter = start To end [Step step] … 処理 … Next [counter]
counter はカウンター役の数値変数で、start が初期値、end が最終値です
古い解説だと To が2回出てくる書き方を見かけますが、それは誤りで、正しくは = start でカウンターに初期値を入れてから To end と続けます
counter は数値が入るので、型は Long や Integer を選びます
下のサンプルは、1から10までの数字をカウンター変数で順番に表示する例です
Dim i As Long
For i = 1 To 10
Debug.Print i
Next iもし start が end より大きく、Step が正のままだと、本体の処理は実行されません
条件を満たさないと判断されて、いきなり Next の次へ進む動きになります
Next の後ろのカウンター名(Next i の i)は、省略して Next だけでも動きます
ただ、入れ子のループになると「どの For に対応する Next なのか」が一目で分かりにくくなるので、書いておくと後から読みやすいです
カウンターの型は、扱う回数の大きさで選びます
数万行を超えるような処理では Integer だと上限(32767)を超えてエラーになることがあるので、行数を回すなら Long を選んでおくのがおすすめです
Stepで増減幅を変える(既定は1・負で逆順)
Step を省略するとカウンターは 1ずつ増える 動きになります
Step を付けると増える幅を自由に変えられて、たとえば奇数だけ回したいときは Step 2 を指定すれば、条件分岐を書かなくても1・3・5…と進みます
For i = 1 To 10 Step 2
Debug.Print i ' ---1,3,5,7,9
Next iStep にマイナスを指定すると、カウンターを減らしながら回せます
このときは end を start より小さくするのがポイントで、下のサンプルは10から1へ逆順に表示します
Dim i As Long
For i = 10 To 1 Step -1
Debug.Print i
Next i逆順はただの小ネタに見えて、実務でしっかり効く場面があります
たとえば行を削除しながら回すとき、上から消すと番号がズレてしまうので、下の行から上へ逆順で回すのが定番のやり方です
最終行まで処理する(実務で一番使う形)
実務でいちばん多いのは「データが入っている最終行まで回したい」というケースです
このときは Cells(Rows.Count, 1).End(xlUp).Row でA列の最終行を取り、その行数まで For Next で回します
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 1 To lastRow
Debug.Print Cells(i, 1).Value
Next iデータの行数は日々変わるので、固定の数字で回すと取りこぼしや空行の処理が起きやすいです
最終行を毎回求めてから回す形にしておくと、行が増えても減ってもそのまま動いてくれます
ここで使っている Cells(Rows.Count, 1) は、シートのいちばん下のセルを指しています
そこから End(xlUp) で上へジャンプすると、データが入っている最後の行に止まるので、その行番号を最終行として使う、という流れです
列の番号(ここでは1=A列)は、いちばんデータが詰まっている列を選ぶのがコツです
途中に空白セルが混ざる列を基準にすると、そこで止まって最終行を取りこぼすことがあるので注意します
二重ループで表(行×列)を処理する
表のように行と列の両方を回したいときは、For Next を入れ子(二重ループ)にします
外側で行を回し、その中でさらに内側のループで列を回す、という組み立てです
Dim r As Long, c As Long
For r = 1 To 3
For c = 1 To 3
Debug.Print Cells(r, c).Value
Next c
Next r入れ子にすると、後で出てくる Exit の挙動に少し注意が必要になります
内側のループで抜けても、抜けるのはその1段だけ、という点は途中抜けのところで改めて触れます
このサンプルは3行×3列の決め打ちですが、実務では行も列も最終位置を求めて回すことが多いです
外側を最終行まで、内側を最終列まで回すようにすると、表の大きさが変わっても同じコードでそのまま処理できます



内側と外側でカウンター変数を別にするのを忘れずに
For Each Next:コレクション・配列をまるごと処理
For Each Next は、複数の要素を持つコレクションや配列を、丸ごと順番に処理するループです
構文は For Each element In group … 処理 … Next [element] という形になります
ループ変数の element は、相手によって向いている型が変わります
セル範囲のようなコレクションが相手ならオブジェクト型(またはVariant)、配列が相手なら Variant を使うのがVBAでのお作法です
For Each の良さは、要素数を自分で数えなくていいところです
対象の数が不定でも「中身ぜんぶ」を相手にしてくれるので、コレクションを扱うときに特に書きやすくなります
For Next との違いは、何番目かを表すカウンターを自分で持たない点です
「3番目だけ処理したい」のように位置で指定したいなら For Next、「中身を順番に全部」でよいなら For Each、と分けて考えると選びやすくなります
セル範囲を1つずつ処理する
まずは定番、セル範囲を1つずつ取り出す例です
下のサンプルは、A1からA10までのセルの値を順番に表示します
Dim cell As Range
For Each cell In Range("A1:A10")
Debug.Print cell.Value
Next cell配列を回す(For Nextでも代替できる)
配列が相手なら、For Each でも For Next でも回せます
For Next を使うときは、LBound と UBound でインデックスの最小値と最大値を取り、その範囲を順番に指定します
下の2つは、どちらも同じ結果になります
Dim sample As Variant
Dim v As Variant
sample = Array("a", "b", "c", "d", "e")
For Each v In sample
Debug.Print v
Next
Dim i As Long
For i = LBound(sample) To UBound(sample)
Debug.Print sample(i)
Next配列の要素数は UBound – LBound + 1 で求められます
LBound が0始まりなのか1始まりなのかを気にせず数えられるので、覚えておくと地味に便利です
For Each で取り出した要素は、基本は「読み取り向き」と考えておくのが安全です
配列の中身そのものを書き換えたいときは、For Next と添字(LBound〜UBound)で要素を直接指す形にすると確実です
ブック内のシートを全部処理する
For Each がいちばん書きやすさを発揮するのが、シートのような「集まり」を相手にするときです
ブックに何枚シートがあるか数えなくても、Worksheets をそのまま渡せば全シートを順番に処理できます
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
Debug.Print ws.Name
Next wsシートの枚数は追加・削除でよく変わるので、枚数を数字で決め打ちするとズレやすいです
For Each なら「いまブックにある分ぜんぶ」を相手にしてくれるので、枚数が変わってもそのまま動きます
同じ書き方で Workbooks を渡せば、開いているブックを順番に処理することもできます
「シートを左から順に」「開いているブックを全部」のような作業は、For Each の出番だと覚えておくと選びやすいです
辞書(Dictionary)やコレクションを回す
キーと値をペアで持てる Dictionary や、要素を順に足していける Collection も、For Each で回せます
件数が決まっていない集計やリスト管理で使うと、要素数を気にせず中身を取り出せて楽です
Dim dic As Object
Set dic = CreateObject("Scripting.Dictionary")
dic.Add "apple", 100
dic.Add "banana", 200
Dim k As Variant
For Each k In dic.Keys
Debug.Print k & " : " & dic(k)
Next kDictionary の場合は Keys を回して、キーから値を取り出すのが定番の形です
受け取る変数の型は、相手が文字列でも数値でも対応できる Variant にしておくと無難です
Do Loop:条件しだいで繰り返す
Do Loop は、条件に応じて繰り返すループです
終了条件を柔軟に決められるので、回数が読めない処理に向いていて、骨組みは Do … 処理 … Loop だけとシンプルです
シンプルなぶん、条件の付け方で動きが変わります
ここでは While・Until・前判定と後判定の違いを、順番に見ていきます
For Next と Do Loop の使い分けは、回数が先に決まるかどうかで考えると分かりやすいです
「10回」「最終行まで」のように回数や終わりが先に分かるなら For Next、「条件を満たすまで」「データが続く限り」のように終わりが読めないなら Do Loop が向いています
Do While(条件が真の間)
While は「条件が真の間、繰り返す」という意味です
Do Loop の中ではいちばんよく使う形で、体感では大半がこの書き方になります
Dim i As Integer
i = 1
Do While i <= 10
Debug.Print i
i = i + 1
Loopここで大事なのが、ループの中でカウンターを i = i + 1 と変化させている点です
これを忘れると条件がいつまでも真のままになり、後で触れる無限ループの原因になります
Do Until(条件が真になるまで)
Until は「条件が真になるまで繰り返す」という意味で、While とは逆向きの考え方です
「この状態になったら終わり」という書き方をしたいときに合います
Dim i As Integer
i = 1
Do Until i > 10
Debug.Print i
i = i + 1
LoopWhile と Until は、慣れるまで頭の中で逆に取りやすいところです
同じ動きを While でも Until でも書けることが多いので、自分が読みやすいと感じる方に寄せておくと迷いません
前判定と後判定(Doの後ろ・Loopの後ろ)
While・Until は、Do の後ろにも Loop の後ろにも書けます
Do の後ろに書くのが前判定、Loop の後ろに書くのが後判定で、両方ちゃんと動きます
Do While i <= 10
' 処理
Loop
Do
' 処理
Loop While i <= 10大きな違いは、後判定だと 条件に関係なく最低1回は処理が実行される 点です
前判定は入る前に条件を見るので0回もありえますが、後判定は中身を1回やってから判定します
後判定が活きるのは「まず1回やってから判定したい」場面です
入力チェックやリトライ処理のように、とりあえず一度実行してから続けるか決めたいときに向いています
While Wend(古い書き方)
While Wend という古い構文もあって、これは Do While Loop と同じ前判定ループの動きをします
誰かが書いた古いコードで見かけることがあるので、読めるようにしておくと十分です
Dim i As Integer
i = 1
While i <= 10
Debug.Print i
i = i + 1
Wend動き自体は Do While Loop と同じ前判定なので、新しく書くなら Do Loop の方が一般的です
あえて While Wend を選ぶ理由は少ないので、読み解き用の知識として持っておけば問題ありません
空セルになるまで下へ回す(実務例)
Do Loop が実務で活きるのは「どこまでデータがあるか分からない」ケースです
最終行を先に求めなくても、セルが空になるまで下へ進む という書き方で、データの終わりまで回せます
Dim i As Long
i = 1
Do While Cells(i, 1).Value <> ""
Debug.Print Cells(i, 1).Value
i = i + 1
LoopFor Next で最終行まで回す形と似ていますが、こちらは行数を先に計算しないのが違いです
データの途中に空行が混ざらない前提なら、書き方がシンプルで読みやすくなります
Withと組み合わせて書きやすくする
同じオブジェクトを何度も書く場面では、With と組み合わせると見通しがよくなります
ループの中で同じシートやセル範囲を繰り返し指すとき、毎回フルで書かずに済むので、コードがすっきりします
Dim i As Long
With ThisWorkbook.Worksheets("Sheet1")
For i = 1 To 10
.Cells(i, 1).Value = i
Next i
End WithWith の中では、先頭にドットを付けるだけで対象のオブジェクトを指せます
シート名を何度も書く手間が減り、後から対象を変えたいときも一か所の修正で済むのが利点です
ループを途中で抜ける・スキップする(Exit / Continue代替)
条件しだいでループを途中でやめたいときは Exit For や Exit Do を使います
他の言語の break にあたる役割で、If や Select Case の中に書いて「ここで抜ける」を表現します
下のコードは1〜4まで表示して、iが5になったところでループを抜けます
For i = 1 To 10
If i = 5 Then Exit For
Debug.Print i
Next iDo Loop でも考え方は同じで、Exit Do を使えば途中で抜けられます
While や Until を付けない Do … Loop でも、中で条件を見て Exit Do すれば終了できます
Do
If 条件 Then Exit Do
' 処理
Loop多重ループで Exit を使っても、抜けるのは そのループ1段だけ です
内側の Exit For で全部のループから抜けられると思い込むと、外側がそのまま回り続けて意図しない動きになります
他の言語にある continue(その回だけスキップして次へ進む)は、VBAにはありません
似た動きは GoTo とラベルで作れて、下のコードは i が5のときだけ表示をスキップします
For i = 1 To 10
If i = 5 Then GoTo Skip
Debug.Print i
Skip:
Next iGoTo は便利に見えますが、増えると処理の流れが追いにくくなってデバッグが大変になります
使うとしても最小限にとどめ、できれば If でくくる形に書き換える方が後で読みやすいです
目的のデータが見つかったら抜ける(検索パターン)
Exit がいちばん役立つのは、リストを上から見ていって「探していたものが見つかったら終わり」にしたいときです
全部回さずに見つかった時点で抜けられるので、データが多いほど処理の無駄を減らせます
Dim i As Long, foundRow As Long
foundRow = 0
For i = 1 To 1000
If Cells(i, 1).Value = "target" Then
foundRow = i
Exit For
End If
Next i
Debug.Print foundRow見つかった行を変数に控えてから Exit For で抜けると、ループの後でその行を使えます
もし最後まで見つからなければ、初期値の0のままなので「無かった」判定にも使えて便利です
無限ループの止め方と防ぎ方
ループを書いていていちばん怖いのが無限ループです
終了条件にたどり着かず、いつまでも処理が終わらない状態で、画面が固まったように見えてヒヤッとします
起きる原因はだいたい決まっていて、条件が変わらないことと、カウンターの更新忘れです
Do While の中で i = i + 1 を書き忘れる、というのが定番のパターンになります
もうひとつ多いのが、終了条件が一生満たされないケースです
たとえば「空セルになるまで」と書いたのに、途中の空行を飛ばす処理を入れてしまうと、終わりにたどり着けず回り続けることがあります
もし無限ループに入ってしまっても、慌てなくて大丈夫です
止めるときは Esc または Ctrl + Break を押せば、実行中の処理を中断できます
VBAの編集画面で Ctrl + Break を押すと処理が止まり、いま実行している行が黄色く反転して教えてくれます
その行のまわりを見れば、どの条件が変わっていないのか・カウンターの更新が抜けていないかを確かめやすくなります
止め方を知っていれば怖くないですが、そもそも起こさないのがいちばんです
無限ループを防ぐコツは、次の3つを意識しておくと大きく減らせます
- ループの中で、条件に関わる値を毎回更新する
- Do内のカウンター更新(i = i + 1 など)を忘れない
- 保険として、一定回数を超えたら Exit Do で抜ける仕掛けを入れておく



固まっても焦らず Esc を押せば戻ってこれますよ
ループを速くする2つのコツ
扱う行数が増えてくると、ループの遅さが気になってきます
処理が重いと感じたときに効きやすい、定番の2つのコツを紹介します
コツ1:配列に一括で読み込んで処理する
セルを1つずつ読み書きすると、そのたびにExcelとのやり取りが発生して時間がかかります
そこで、セル範囲をいったん配列にまとめて読み込み、ループで処理してから一括で書き戻すと、ぐっと速くなることが多いです
Dim data As Variant
data = Range("A1:A10000").Value ' セル範囲を一括で配列に読み込む
Dim i As Long
For i = 1 To UBound(data, 1)
data(i, 1) = data(i, 1) * 2
Next i
Range("A1:A10000").Value = data ' 配列を一括で書き戻す複数セルのRangeをValueで受け取ると、中身は2次元配列になります
だから添字は data(行, 列) の形になり、A列1列でも data(i, 1) のように列番号の1が要ります
なぜ速くなるかというと、セルへのアクセスは1回ごとにExcel側とのやり取りが走るからです
1万行を1つずつ読み書きすると、そのやり取りが1万回起きてしまいますが、配列なら読み込みと書き戻しの2回で済むので、処理時間に差が出ます
行数が数百くらいなら体感差は小さいですが、数千・数万と増えるほど効いてきます
「ループが重いな」と感じたら、まずこの配列一括の形に書き換えられないか考えてみると改善しやすいです
コツ2:画面更新をオフにする
重いループの間、Excelが画面をいちいち描き直すのも遅さの一因です
Application.ScreenUpdating = False で更新を止めてからループを回すと、見た目のちらつきも処理時間も抑えられます
Application.ScreenUpdating = False
' ここで重い繰り返し処理を実行
Application.ScreenUpdating = Trueここで大事なのが、処理が終わったら忘れず = True に戻すことです
戻し忘れると画面が固まったように見えてしまうので、オフにしたらセットで戻す、とペアで覚えておきましょう
同じ発想で、自動計算を Application.Calculation = xlCalculationManual で一時的に止める手もあります
関数が多く入ったシートだと、書き込むたびに再計算が走って重くなるので、ループの間だけ止めると効きます
これも処理後に xlCalculationAutomatic へ戻すのを忘れないようにします
軽い処理にまで毎回これを使う必要はありません
行数が多くて重いと感じたループだけに使えば十分で、まずは普通に書いてみて遅かったら足す、くらいの感覚で問題ありません
まとめ:構文の使い分け早見表
最後に、ここまでの内容を早見表にまとめます
判断の目安はシンプルで、回数が決まるなら For Next、集まりを全部なら For Each、条件しだいなら Do Loop、まず1回やりたいなら後判定です
| 構文 | 向いている場面 | 覚えておく点 |
|---|---|---|
| For Next | 繰り返す回数が決まっている | Step で増減や逆順、最終行まで回す定番 |
| For Each | コレクションや配列を全部処理 | 要素は読み取り向き、書き換えは For Next 添字 |
| Do While / Until | 回数が読めず条件で続けたい | 前判定と後判定、後判定は最低1回 |
| While Wend | 古い書き方(読めれば十分) | いまは Do While Loop が一般的 |
| Exit For / Exit Do | 条件で途中で抜けたい | 多重ループでは1段だけ抜ける |
| GoTo(continue代替) | 今回だけスキップしたい | VBAにContinueは無い、多用しない |
ループはVBAの基礎ですが、ここを押さえると書けるマクロの幅が一気に広がります
まずは For Next と Do While あたりから手を動かして、必要になったら For Each や高速化のコツを足していくのがおすすめです
ループと組み合わせると便利なテーマとして、データを扱う型まわりの知識があります
変数や型をもう一段固めたい方はVBAの変数と定数の解説記事、JSONのようなデータ処理に進みたい方はVBAでJSONを扱う記事もあわせてどうぞ











コメント