VBA For Eachの使い方 — セル・シート・配列を1行でループ処理

スポンサーリンク

「セル範囲を全部チェックしたいのに、番号の指定が面倒……」

そんな悩み、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

変数wsWorksheet型で宣言するのがポイントです。

ひとつ注意があります。
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 EachFor~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が起動します。

リボンから開く場合は「開発」タブを使います。
開発タブが表示されていない場合は、次の手順で追加してください。

  1. 「ファイル」→「オプション」→「リボンのユーザー設定」を開く
  2. 右側の一覧で「開発」にチェックを入れる
  3. 「OK」をクリックする

標準モジュールの挿入と実行

VBEを開いたら、コードを書く場所を用意します。

  1. メニューの「挿入」→「標準モジュール」をクリック
  2. 表示されたコードウィンドウにコードを貼り付ける
  3. F5キーを押すか、メニューの「実行」→「Sub/ユーザーフォームの実行」で実行

VBAの基本から体系的に学びたい方は、VBA学習ロードマップも参考にしてみてください。

まとめ

この記事では、VBAのFor Each~Nextについて解説しました。

  • 基本構文: For Each 変数 In コレクション ... Next
  • セル範囲: Rangeを指定して全セルを一括処理
  • 全シート: Worksheetsで全シートをまとめて処理
  • 配列: Variant型の変数で要素を読み取り
  • 使い分け: コレクションがあればFor Each、回数指定ならFor~Next

For Eachを使いこなすと、繰り返し処理がぐっとシンプルになります。
まずはセル範囲のループから、ぜひ試してみてくださいね。

なお、作成したマクロは.xlsm(マクロ有効ブック)形式で保存してください。
.xlsxで保存するとマクロが消えてしまうので注意です。

タイトルとURLをコピーしました