# VBAのFor Nextで繰り返し処理｜最終行まで・逆順・途中で抜ける書き方

Excel VBA の For...Next で、表の 2 行目から最終行まで同じ処理を繰り返す書き方を、コピーして動くコード付きで解説します。Step で 1 つ飛ばし・逆順にする方法、行を消すときに下から回す理由、Exit For で途中で抜ける方法、For Each との使い分けまで Microsoft の公式リファレンスで確かめました。

<Points>

- VBA の繰り返しは `For i = 開始 To 終了` ～ `Next i` で書き、`i` が 1 ずつ増えながら間の処理を繰り返す
- 表の最終行は `Cells(Rows.Count, "A").End(xlUp).Row` で求め、`For i = 2 To lastRow` とすれば行が増えても直さずに済む
- 行を削除するときは `Step -1` で下から回す。途中で止めたいときは `Exit For` を使う

</Points>

## For...Nextでできること

注文の一覧の全行で「単価 × 数量」を計算する、条件に合う行に印を付ける、といった作業は、1 行分の処理を書いて行の数だけ繰り返せば終わります。この「繰り返し」を書くのが `For...Next` です。

[Microsoft の公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/fornext-statement)では、ループ カウンター (数を数える変数) が最後の値に近づく間、処理を繰り返す命令として説明されています。

## 基本の書き方

```vb
For カウンター = 開始の値 To 終了の値 [Step 増やす量]
    繰り返す処理
Next カウンター
```

<Figure title="For...Nextの各部分" source="Microsoft Learn「For...Next ステートメント (VBA)」">

| 部分 | 意味 | 例 |
|---|---|---|
| カウンター | 回数を数える数値の変数 | `i` |
| 開始の値 | カウンターの最初の値 | `2` |
| 終了の値 | カウンターの最後の値 | `lastRow` |
| Step | 1 回ごとにカウンターを増やす量。省略すると 1 | `Step -1` |

</Figure>

まずは A1 から A10 に 1 から 10 の数を入れる例です。VBE の標準モジュールに貼り付けて実行してください (VBE の開き方は [Excelマクロの作り方](/excel-macro/) で説明しています)。

```vb
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` のように決め打ちにせず、最終行をコードで求めます。

<Figure title="注文シートの例" caption="D 列の金額をマクロで計算します。">

| | A | B | C | D |
|---|---|---|---|---|
| 1 | 商品 | 単価 | 数量 | 金額 |
| 2 | コピー用紙 | 2800 | 10 | |
| 3 | トナー | 18000 | 2 | |
| 4 | クリアファイル | 30 | 50 | |

</Figure>

```vb
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)` で上に向かってデータのある最初のセルまで移動します。[公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/excel.range.end)のとおり、`End` は End キーと方向キーを押す操作と同じ動きをします。その行番号 (`.Row`) が最終行です。

見出しが 1 行目にあるので、繰り返しは 2 行目から始めています。

## 1つ飛ばし・逆順にする (Step)

`Step` を付けると、カウンターの増やし方を変えられます。

```vb
For i = 2 To lastRow Step 2
    Cells(i, "A").Interior.Color = RGB(235, 245, 238)
Next i
```

この例は 2 行目、4 行目、6 行目…と 1 行おきに A 列へ薄い色を付けます。[公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/api/excel.interior.color)のとおり、色の値は `RGB` 関数で作ります。

`Step` にマイナスの値を書くと、カウンターは減っていきます。公式リファレンスのとおり、`Step` が正か 0 のときは「カウンターが終了の値以下の間」、負のときは「カウンターが終了の値以上の間」繰り返します。

### 行を削除するときは下から回す

条件に合う行を消すときは、必ず下の行から上へ回します。

```vb
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 の基礎知識](https://learn.microsoft.com/ja-jp/office/vba/library-reference/concepts/getting-started-with-vba-in-office)の例でも、削除のたびに数が減るためカウンターを減らしながら回す書き方が使われています。

<Note tone="caution">

行を消すマクロは元に戻せません。動かす前にブックを別名で保存しておくなど、元のデータを残してから試してください。

</Note>

## 途中で抜ける (Exit For)

探していた値が見つかったら、それ以上繰り返す必要はありません。`Exit For` を使うと、その場でループを抜けて `Next` の次の行へ進みます。

```vb
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` を入れると、行と列の両方を順に回せます。公式リファレンスのとおり、それぞれのループには別の名前のカウンターを使います。

```vb
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` も使えます。[公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/for-eachnext-statement)では、配列やコレクションの各要素に対して処理を繰り返す命令として説明されています。

```vb
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
```

<Compare>
<Column title="For...Next">

- 行番号など数を使って回す
- 逆順や 1 つ飛ばしができる
- 行を消す処理に向く

</Column>
<Column title="For Each...Next" tone="accent">

- 範囲やシートの全部を順に回す
- 番号を数えなくてよい
- 全シートの処理などに向く

</Column>
</Compare>

## 自分で作るのが難しいときは

`For...Next` が書けると、表の全行への処理はたいてい自動にできます。ただ、数万行を 1 セルずつ読み書きすると時間がかかる、途中でエラーが出ると中途半端な状態で止まる、といった問題も出てきます。

速さやエラー時の止め方まで考えたマクロを作りたい、既存のマクロが遅くて困っているといったときは、シートナビの[相談フォーム](/contact/)からお気軽にご相談ください。

## よくある質問

### Q. ループの中でカウンターの値を変えてもよいですか？

動きはしますが、公式リファレンスでは、ループの中でカウンターを変えるとコードが読みにくく、不具合を探しにくくなると注意されています。飛ばしたい行があるときは、カウンターを変えずに `If` で処理を飛ばします。

### Q. Next の後ろのカウンター名は省略できますか？

省略できます。公式リファレンスのとおり、`Next` だけでも同じように動きます。ただ、二重のループでは `Next c`、`Next r` と書いておくと、どのループの終わりかがわかりやすくなります。

### Q. 回数が決まっていない繰り返しはどう書きますか？

「空のセルが出るまで」のように回数が決まっていない繰り返しは、`Do While 条件` ～ `Loop` で書きます。[公式リファレンス](https://learn.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/doloop-statement)のとおり、条件が True の間、処理を繰り返します。途中で抜けるときは `Exit For` の代わりに `Exit Do` を使います。
