「セル範囲を全部チェックしたいのに、番号の指定が面倒……」
そんな悩み、VBAを書いていると一度は感じますよね。
ループ回数を自分で管理するのは手間ですし、範囲が変わるたびにコードを直すのも大変です。
For Each~Nextを使えば、対象のセルやシートをまるごとループできます。
番号の管理が不要になり、コードもすっきり書けますよ。
この記事では、For Eachの基本構文から実務パターンまでまとめて解説します。
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が便利です。
使い分けの詳しい判断軸は、記事の後半で解説しますね。
【パターン1】セル範囲を一括処理する
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
【パターン2】全シートに同じ処理をする
ブック内の全シートにまとめて処理をかけたいとき、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のように、シート名で判定してください。
【パターン3】配列のループに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~Nextとどちらが向いている?比較まとめ
配列のループでは、For~Nextのほうが向いているケースもあります。
| 比較項目 | For Each | For~Next |
|---|---|---|
| インデックス(番号)の取得 | できない | できる |
| 要素の書き換え | できない(読み取り専用) | できる |
| コードのシンプルさ | シンプル | やや冗長 |
| 変数の型 | Variant限定 | 自由に指定可 |
配列の要素を読み取るだけならFor Eachが手軽です。
要素の書き換えや番号が必要な処理には、For~Nextを選びましょう。
For EachとFor~Next どちらを使えばいい?
ここまで3つのパターンを見てきました。
「結局どっちを使えばいいの?」と迷ったときの判断軸をまとめます。
使い分けの判断軸まとめ
| やりたいこと | おすすめ |
|---|---|
| セル範囲に同じ処理をしたい | For Each |
| 全シートに同じ処理をしたい | For Each |
| 配列を読み取りたい | For Each |
| ループ回数が決まっている | For~Next |
| インデックス番号が必要 | For~Next |
| 配列の要素を書き換えたい | For~Next |
| 条件で繰り返し回数が変わる | Do Loop |
迷ったら「対象のまとまりがあるか」で判断するのがコツです。
Range・WorksheetsなどのコレクションがあるならFor Eachです。
回数やインデックスが重要ならFor~Nextを選びましょう。
よくあるエラーについても触れておきます。
配列でVariant以外の型を使うと型の不一致エラーになります。
また、オブジェクト変数にSetを付け忘れるとエラー91が発生します。
変数の型宣言は慎重に行ってくださいね。
まとめ
この記事では、VBAのFor Each~Nextについて解説しました。
- 基本構文:
For Each 変数 In コレクション ... Next - セル範囲: Rangeを指定して全セルを一括処理
- 全シート: Worksheetsで全シートをまとめて処理
- 配列: Variant型の変数で要素を読み取り
- 使い分け: コレクションがあればFor Each、回数指定ならFor~Next
For Eachを使いこなすと、繰り返し処理がぐっとシンプルになります。
まずはセル範囲のループから、ぜひ試してみてくださいね。
なお、作成したマクロは.xlsm(マクロ有効ブック)形式で保存してください。.xlsxで保存するとマクロが消えてしまうので注意です。
