For...Nextでできること
注文の一覧の全行で「単価 × 数量」を計算する、条件に合う行に印を付ける、といった作業は、1 行分の処理を書いて行の数だけ繰り返せば終わります。この「繰り返し」を書くのが For...Next です。
Microsoft の公式リファレンスでは、ループ カウンター (数を数える変数) が最後の値に近づく間、処理を繰り返す命令として説明されています。
基本の書き方
For カウンター = 開始の値 To 終了の値 [Step 増やす量]
繰り返す処理
Next カウンター
For...Nextの各部分
| 部分 | 意味 | 例 |
|---|---|---|
| カウンター | 回数を数える数値の変数 | i |
| 開始の値 | カウンターの最初の値 | 2 |
| 終了の値 | カウンターの最後の値 | lastRow |
| Step | 1 回ごとにカウンターを増やす量。省略すると 1 | Step -1 |
まずは A1 から A10 に 1 から 10 の数を入れる例です。VBE の標準モジュールに貼り付けて実行してください (VBE の開き方は Excelマクロの作り方 で説明しています)。
Sub FillNumbers()
Dim i As Long
For i = 1 To 10
Cells(i, 1).Value = i
Next i
End Sub
Cells(行, 列) は、行と列の番号でセルを指す書き方です。i が 1、2、3…と増えるので、Cells(i, 1) は A1、A2、A3…と 1 つずつ下のセルを指します。
表の最終行まで繰り返す
実際の表は行の数が毎回変わります。終了の値を 10 のように決め打ちにせず、最終行をコードで求めます。
注文シートの例
| A | B | C | D | |
|---|---|---|---|---|
| 1 | 商品 | 単価 | 数量 | 金額 |
| 2 | コピー用紙 | 2800 | 10 | |
| 3 | トナー | 18000 | 2 | |
| 4 | クリアファイル | 30 | 50 |
Sub CalcAmount()
Dim lastRow As Long
Dim i As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
For i = 2 To lastRow
Cells(i, "D").Value = Cells(i, "B").Value * Cells(i, "C").Value
Next i
End Sub
Cells(Rows.Count, "A") はシートの A 列の一番下のセルで、そこから .End(xlUp) で上に向かってデータのある最初のセルまで移動します。公式リファレンスのとおり、End は End キーと方向キーを押す操作と同じ動きをします。その行番号 (.Row) が最終行です。
見出しが 1 行目にあるので、繰り返しは 2 行目から始めています。
1つ飛ばし・逆順にする (Step)
Step を付けると、カウンターの増やし方を変えられます。
For i = 2 To lastRow Step 2
Cells(i, "A").Interior.Color = RGB(235, 245, 238)
Next i
この例は 2 行目、4 行目、6 行目…と 1 行おきに A 列へ薄い色を付けます。公式リファレンスのとおり、色の値は RGB 関数で作ります。
Step にマイナスの値を書くと、カウンターは減っていきます。公式リファレンスのとおり、Step が正か 0 のときは「カウンターが終了の値以下の間」、負のときは「カウンターが終了の値以上の間」繰り返します。
行を削除するときは下から回す
条件に合う行を消すときは、必ず下の行から上へ回します。
Sub DeleteCanceledRows()
Dim lastRow As Long
Dim i As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
For i = lastRow To 2 Step -1
If Cells(i, "E").Value = "取消" Then
Rows(i).Delete
End If
Next i
End Sub
E 列が「取消」の行を消すコードです。上から回すと、行を消したときに下の行が 1 つ上に詰まり、詰まった行を調べずに次へ進んでしまいます。下から回せば、消した行より上の行の番号は変わらないので、取りこぼしが起きません。公式ドキュメントの Office VBA の基礎知識の例でも、削除のたびに数が減るためカウンターを減らしながら回す書き方が使われています。
途中で抜ける (Exit For)
探していた値が見つかったら、それ以上繰り返す必要はありません。Exit For を使うと、その場でループを抜けて Next の次の行へ進みます。
Sub FindFirstOutOfStock()
Dim lastRow As Long
Dim i As Long
Dim foundRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
foundRow = 0
For i = 2 To lastRow
If Cells(i, "C").Value = 0 Then
foundRow = i
Exit For
End If
Next i
If foundRow = 0 Then
MsgBox "在庫 0 の商品はありません"
Else
MsgBox foundRow & " 行目の " & Cells(foundRow, "A").Value & " が在庫 0 です"
End If
End Sub
C 列 (在庫数) が 0 の最初の行を探して知らせます。公式リファレンスのとおり、Exit For はループの中のどこにでも何個でも置けて、If...Then で条件を調べたあとに使うのが一般的です。
二重のループ
For...Next の中に別の For...Next を入れると、行と列の両方を順に回せます。公式リファレンスのとおり、それぞれのループには別の名前のカウンターを使います。
Sub ClearNegativeValues()
Dim r As Long
Dim c As Long
For r = 2 To 13
For c = 2 To 6
If Cells(r, c).Value < 0 Then
Cells(r, c).ClearContents
End If
Next c
Next r
End Sub
B2 から F13 の範囲で、マイナスの値が入ったセルを空にします。
For Eachとの使い分け
セル範囲やシートの「全部」を順に処理するなら、For Each...Next も使えます。公式リファレンスでは、配列やコレクションの各要素に対して処理を繰り返す命令として説明されています。
Sub ListSheetNames()
Dim sheet As Worksheet
Dim outputRow As Long
outputRow = 1
For Each sheet In ThisWorkbook.Worksheets
Worksheets(1).Cells(outputRow, "H").Value = sheet.Name
outputRow = outputRow + 1
Next sheet
End Sub
For...Next
- 行番号など数を使って回す
- 逆順や 1 つ飛ばしができる
- 行を消す処理に向く
For Each...Next
- 範囲やシートの全部を順に回す
- 番号を数えなくてよい
- 全シートの処理などに向く
自分で作るのが難しいときは
For...Next が書けると、表の全行への処理はたいてい自動にできます。ただ、数万行を 1 セルずつ読み書きすると時間がかかる、途中でエラーが出ると中途半端な状態で止まる、といった問題も出てきます。
速さやエラー時の止め方まで考えたマクロを作りたい、既存のマクロが遅くて困っているといったときは、シートナビの相談フォームからお気軽にご相談ください。
よくある質問
ループの中でカウンターの値を変えてもよいですか?
動きはしますが、公式リファレンスでは、ループの中でカウンターを変えるとコードが読みにくく、不具合を探しにくくなると注意されています。飛ばしたい行があるときは、カウンターを変えずに If で処理を飛ばします。
Next の後ろのカウンター名は省略できますか?
省略できます。公式リファレンスのとおり、Next だけでも同じように動きます。ただ、二重のループでは Next c、Next r と書いておくと、どのループの終わりかがわかりやすくなります。
回数が決まっていない繰り返しはどう書きますか?
「空のセルが出るまで」のように回数が決まっていない繰り返しは、Do While 条件 ~ Loop で書きます。公式リファレンスのとおり、条件が True の間、処理を繰り返します。途中で抜けるときは Exit For の代わりに Exit Do を使います。


