「セル範囲を全部チェックしたいのに、番号の指定が面倒……」
そんな悩み、VBAを書いていると一度は感じますよね。
ループ回数を自分で管理するのは手間ですし、範囲が変わるたびにコードを直すのも大変です。
For Each~Nextを使えば、対象のセルやシートをまるごとループできます。
番号の管理が不要になり、コードもすっきり書けますよ。
この記事では、For Eachの基本構文から実務パターンまでまとめて解説します。
VBA For Each~Nextとは?基本の書き方をおさらい
For Each~Nextは、コレクション(まとまり)の中身を1つずつ取り出して処理するループ構文です。
「セル範囲のすべてのセル」「ブック内のすべてのシート」など、グループの要素をまとめて処理したいときに使います。
基本の構文は次のとおりです。
For Each 変数 In コレクション
'--- 繰り返したい処理 ---
Next 変数
変数にはコレクションの要素が1つずつ代入されます。
すべての要素を処理し終わると、自動的にループを抜けます。
ポイントは、ループの回数を指定しなくてよいことです。
コレクションの要素数が変わっても、コードの修正は不要ですよ。
For~Nextとの違いはなに?
For~Nextは、回数を指定して繰り返すループ構文です。
一方、For Eachは対象のまとまりを順に処理する構文です。
ざっくりまとめると、こんなイメージになります。
- For~Next: 「1番目から10番目まで処理して」
- For Each: 「この中の全部を処理して」
回数が決まっている処理にはFor~Nextが向いています。
「全部に同じ処理をしたい」ならFor Eachが便利です。
使い分けの詳しい判断軸は、記事の後半で解説しますね。
For Eachでセル範囲を一括処理する
For Eachでもっともよく使うのが、セル範囲のループです。
指定した範囲のすべてのセルに、同じ処理を適用できます。
Rangeに対してFor Eachを使う基本構文
セル範囲をFor Eachで処理するときは、Rangeオブジェクトをコレクションに指定します。
Sub セル範囲をループ()
Dim cell As Range '--- 処理対象のセル ---
For Each cell In Range("A1:A10")
cell.Value = cell.Value * 2 '--- 値を2倍にする ---
Next cell
End Sub
cellには、A1、A2、A3……と順にセルが代入されます。
各セルの値を2倍にする、シンプルな処理ですね。
なお、セルの処理順序は公式には保証されていません。
通常は左上から右下へ処理されますが、順序に依存するコードは避けるのがベターです。
実務サンプル:指定範囲のセルに処理を一括適用
実務では、動的な範囲を対象にすることが多いです。
最終行の取得と組み合わせたサンプルを見てみましょう。
Sub 空欄セルを強調表示()
Dim lastRow As Long '--- 最終行 ---
Dim cell As Range '--- 処理対象のセル ---
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
For Each cell In Range("A1:C" & lastRow)
If cell.Value = "" Then
cell.Interior.Color = RGB(255, 200, 200) '--- 薄い赤で塗る ---
End If
Next cell
End Sub
A列の最終行までの範囲で、空欄セルを薄い赤色にハイライトします。
データの入力漏れチェックに、そのまま使えますよ。
ループの途中で処理を抜けたいときは、Exit Forを使います。
最初の空欄が見つかった時点で止めるなら、こう書きます。
If cell.Value = "" Then
MsgBox cell.Address & " が空欄です"
Exit For '--- 最初の空欄で停止 ---
End If
なお、ループ内でIf文を組み合わせるのは定番パターンです。
条件に合うセルだけを対象にしたいときに活用してくださいね。
For Eachで全シートに同じ処理をする
ブック内の全シートにまとめて処理をかけたいとき、For Eachが活躍します。
シート数が増減しても、コードの変更は不要です。
WorksheetsコレクションとFor Eachの組み合わせ
WorksheetsコレクションをFor Eachに渡すと、全シートを順に処理できます。
Sub 全シート名を表示()
Dim ws As Worksheet '--- 処理対象のシート ---
For Each ws In Worksheets
Debug.Print ws.Name '--- イミディエイトウィンドウに出力 ---
Next ws
End Sub
変数wsはWorksheet型で宣言するのがポイントです。
ひとつ注意があります。Worksheetsは非表示のシートも含みます。xlSheetVeryHiddenで隠したシートも対象になるので、気をつけてください。
表示シートだけ処理したいときは、条件を追加しましょう。
実務サンプル:全シートのA1セルをクリアする
Sub 全シートA1クリア()
Dim ws As Worksheet '--- 処理対象のシート ---
For Each ws In Worksheets
If ws.Visible = xlSheetVisible Then '--- 表示シートのみ ---
ws.Range("A1").ClearContents
End If
Next ws
End Sub
ws.Visible = xlSheetVisibleの条件で、表示中のシートだけを対象にしています。
特定のシートを除外したい場合もあるでしょう。
そのときはIf ws.Name <> "集計" Thenのように、シート名で判定してください。
実務サンプル:全シートにヘッダーを一括設定する
月別シートを持つブックで、全シートに同じヘッダーを設定するコードです。
Sub 全シートにヘッダー設定()
Dim ws As Worksheet '--- 処理対象のシート ---
For Each ws In Worksheets
If ws.Visible = xlSheetVisible Then '--- 表示シートのみ ---
ws.Range("A1").Value = "日付"
ws.Range("B1").Value = "担当者"
ws.Range("C1").Value = "金額"
ws.Range("A1:C1").Font.Bold = True '--- ヘッダーを太字 ---
End If
Next ws
MsgBox "全シートにヘッダーを設定しました"
End Sub
毎月シートを追加するようなブックで、ヘッダーの設定漏れを防げます。
手動で1枚ずつ入力するよりも、ずっと確実ですよ。
For Eachで配列をループする
For Eachは配列のループにも使えます。
ただし、注意点があるので確認しておきましょう。
配列に対してFor Eachを使う書き方
Sub 配列をループ()
Dim arr As Variant '--- 配列 ---
Dim item As Variant '--- 配列の要素(Variant型が必須) ---
arr = Array("東京", "大阪", "名古屋")
For Each item In arr
Debug.Print item
Next item
End Sub
ここで大事なポイントがあります。
配列をFor Eachで回すとき、変数は必ずVariant型にしてください。Dim item As Stringのように宣言すると、型の不一致エラーになります。
コレクション(Worksheetsなど)では専用の型が使えます。
しかし、配列はVariant限定です。
つまずきやすいので覚えておきましょう。
配列でのFor Each vs For~Nextの比較
配列のループでは、For~Nextのほうが向いているケースもあります。
| 比較項目 | For Each | For~Next |
|---|---|---|
| インデックス(番号)の取得 | できない | できる |
| 要素の書き換え | できない(読み取り専用) | できる |
| コードのシンプルさ | シンプル | やや冗長 |
| 変数の型 | Variant限定 | 自由に指定可 |
配列の要素を読み取るだけならFor Eachが手軽です。
要素の書き換えや番号が必要な処理には、For~Nextを選びましょう。
VBA For Eachの使い分け判断チャート
ここまで3つのパターンを見てきました。
「結局どのループを使えばいいの?」と迷ったときの判断軸をまとめます。
3つのループ構文の使い分け
| やりたいこと | おすすめの構文 |
|---|---|
| セル範囲に同じ処理をしたい | For Each |
| 全シートに同じ処理をしたい | For Each |
| 配列を読み取りたい | For Each |
| ループ回数が決まっている | For~Next |
| インデックス番号が必要 | For~Next |
| 配列の要素を書き換えたい | For~Next |
| 条件で繰り返し回数が変わる | Do Loop |
迷ったら「対象のまとまりがあるか」で判断するのがコツです。
Range・WorksheetsなどのコレクションがあるならFor Eachです。
回数やインデックスが重要ならFor~Nextを選びましょう。
For Eachでよくあるエラーと対処法
For Eachを使っていて発生しやすいエラーをまとめました。
| エラー | 原因 | 対処法 |
|---|---|---|
| 型が一致しません(エラー13) | 配列のループ変数をVariant以外で宣言した | Dim item As Variantに変更する |
| オブジェクト変数またはWithブロック変数が設定されていません(エラー91) | オブジェクト変数へのSet忘れ | Set cell = Range("A1")のようにSetを付ける |
| コンパイルエラー: Next に対する For がありません | Nextの変数名がFor Eachと不一致 | For Each cellならNext cellと揃える |
| 実行時エラー: コレクションは変更できません | ループ内でコレクションの要素を追加・削除した | ループ外で削除対象を配列に格納し、後からまとめて削除する |
特に「型が一致しません」は初心者がつまずきやすいエラーです。
配列のループでは、必ずVariant型を使ってください。
ループ内でシートを削除したいときの対処
For Eachのループ中にコレクションを変更すると、エラーになります。
シートを削除したい場合は、逆順ループで対処しましょう。
Sub 空シートを削除()
Dim i As Long '--- ループカウンター ---
Application.DisplayAlerts = False '--- 確認ダイアログを非表示 ---
For i = Worksheets.Count To 1 Step -1
If WorksheetFunction.CountA(Worksheets(i).UsedRange) = 0 Then
Worksheets(i).Delete
End If
Next i
Application.DisplayAlerts = True '--- 確認ダイアログを復帰 ---
End Sub
逆順(Step -1)にするのがポイントです。
順方向だと削除後にインデックスがずれて、正しく処理できません。
このパターンはFor~Nextの逆順ループが適しています。
VBEの起動方法(はじめてマクロを使う方へ)
VBAのコードは、VBE(Visual Basic Editor)で入力して実行します。
はじめてマクロを使う方は、以下の手順で準備してくださいね。
VBEの開き方
キーボードで Alt + F11 を押すと、VBEが起動します。
リボンから開く場合は「開発」タブを使います。
開発タブが表示されていない場合は、次の手順で追加してください。
- 「ファイル」→「オプション」→「リボンのユーザー設定」を開く
- 右側の一覧で「開発」にチェックを入れる
- 「OK」をクリックする
標準モジュールの挿入と実行
VBEを開いたら、コードを書く場所を用意します。
- メニューの「挿入」→「標準モジュール」をクリック
- 表示されたコードウィンドウにコードを貼り付ける
- F5キーを押すか、メニューの「実行」→「Sub/ユーザーフォームの実行」で実行
VBAの基本から体系的に学びたい方は、VBA学習ロードマップも参考にしてみてください。
まとめ
この記事では、VBAのFor Each~Nextについて解説しました。
- 基本構文:
For Each 変数 In コレクション ... Next - セル範囲: Rangeを指定して全セルを一括処理
- 全シート: Worksheetsで全シートをまとめて処理
- 配列: Variant型の変数で要素を読み取り
- 使い分け: コレクションがあればFor Each、回数指定ならFor~Next
For Eachを使いこなすと、繰り返し処理がぐっとシンプルになります。
まずはセル範囲のループから、ぜひ試してみてくださいね。
なお、作成したマクロは.xlsm(マクロ有効ブック)形式で保存してください。.xlsxで保存するとマクロが消えてしまうので注意です。
