Excel VBAでセルを操作するとき、RangeとCellsのどちらを使うか迷いませんか。
書き方がまったく違うので、「結局どっちが正解なの?」と手が止まりがちですよね。使い分けを間違えると、ループ処理でセル番地の文字列結合が必要になったり、別シート操作で1004エラーに悩まされたりします。
この記事では、RangeとCellsの違いを比較表で整理し、実務シナリオごとの選び方をお伝えします。読み終わるころには「この場面ならこっち」と迷わず選べるようになりますよ。
NOTE
VBAを初めて触る方は、先に「VBE画面の見方」をチェックしておくとスムーズです。
RangeとCellsの違いを一覧でおさらい
まず結論から整理しましょう。RangeとCellsはどちらも「セルを指定する方法」ですが、得意な場面が違います。
| 比較項目 | Range | Cells |
|---|---|---|
| 書き方 | Range("A1") | Cells(1, 1) |
| 指定方法 | アドレス文字列 | 行番号・列番号(数値) |
| 複数セル範囲 | Range("A1:C10") で直接指定 | 単体では1セルのみ |
| 名前付き範囲 | Range("売上合計") で参照可 | 非対応 |
| 変数との相性 | 文字列結合が必要 | 数値をそのまま渡せる |
| ループ処理 | やや冗長になる | スッキリ書ける |
ひとことで言えば、「文字列で指定するか、数値で指定するか」の違いです。この違いが使い分けの根拠になっています。
Range:アドレス直書きでわかりやすい
RangeはExcelシート上の「A1」形式をそのまま使えます。普段のExcel操作と同じ感覚なので、直感的に読み書きできるのが強みです。
' 1つのセルに値を入力
Range("A1").Value = "こんにちは"
' 範囲をまとめて太字にする
Range("A1:C10").Font.Bold = True
' 離れたセルを一括指定
Range("A1,C3,E5").Font.Color = vbRed
Rangeの詳しい使い方は「VBA Rangeの使い方」でも解説しています。
Cells:行番号・列番号で指定できる
Cellsは行と列を数値で指定します。「Cells(行, 列)」の形で、列もアルファベットではなく数字で書くのがポイントです。
' A1セル(1行目・1列目)に値を入力
Cells(1, 1).Value = "こんにちは"
' B3セル(3行目・2列目)に値を入力
Cells(3, 2).Value = 100
数値だけで指定するので、変数と組み合わせやすいのが最大の強みです。
VBA Cellsを使うべき場面
Cellsが本領を発揮するのは、セルの位置を動的に変えたいときです。
For文でループするとき
Cellsの最大の強みは、変数をそのまま行番号に渡せることです。
' A列の1行目〜10行目に連番を入力
Dim i As Long
For i = 1 To 10
Cells(i, 1).Value = i
Next i
同じ処理をRangeで書くとこうなります。
' Rangeだと文字列結合が必要
Dim i As Long
For i = 1 To 10
Range("A" & i).Value = i
Next i
動きは同じですが、"A" & i と文字列結合が入ります。列も変数にしたい場合はさらに複雑になるので、ループ処理ではCellsがおすすめです。
For文の書き方をもっと知りたい方は「VBA For文の使い方」もチェックしてみてください。
行列を動的に計算したいとき
行も列も変数で動かしたい場合、Cellsの数値指定が活きます。
' 5×5の掛け算表を作る
Dim r As Long ' 行カウンター
Dim c As Long ' 列カウンター
For r = 1 To 5
For c = 1 To 5
Cells(r, c).Value = r * c
Next c
Next r
二重ループとの相性は抜群です。Rangeでこれをやると、列番号をアルファベットに変換する処理が必要になり、かなり面倒になります。
変数(Dim)の宣言ルールが気になる方は「変数の使い方とルール」を参照してください。宣言を強制するOption Explicitもあわせて覚えておくと安心ですよ。
VBA Rangeを使うべき場面
一方、Rangeが適しているのは「セルの位置が決まっている」場面です。
セルアドレスが固定のとき
操作対象が固定セルなら、Rangeが読みやすいです。
' 決まったセル範囲をクリアする
Range("A1:D1").ClearContents
' ヘッダー行を太字にする
Range("A1:F1").Font.Bold = True
「A1:D1」とそのまま書けるので、コードを読んだ人がすぐに対象範囲を把握できます。可読性の高さがRangeの大きなメリットです。
名前付き範囲を指定するとき
Excelで名前を定義している場合、Rangeから直接参照できます。
' 名前定義「売上合計」の値を取得
Dim total As Long
total = Range("売上合計").Value
名前付き範囲はCellsでは参照できません。名前定義を使う場面ではRangeの一択になります。
セルの位置が変わってもコードを修正しなくて済むので、実務ではとても便利ですよ。
Range(Cells, Cells)の組み合わせ技
RangeとCellsは組み合わせて使えます。これを覚えると、動的な範囲指定がぐっと楽になります。
基本構文
Range(Cells(開始行, 開始列), Cells(終了行, 終了列)) の形で書きます。
' A1からE10までを選択
Range(Cells(1, 1), Cells(10, 5)).Select
開始位置も終了位置も数値で制御できるのがポイントです。固定範囲にはRange単体、動的範囲にはこの組み合わせと覚えておきましょう。
開始・終了行を動的に変える実例
実務で最もよく使うのが、最終行を取得して動的に範囲を決めるパターンです。
Sub 動的範囲に罫線を引く()
' A列の最終行を取得
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
' A1から最終行のC列まで罫線を引く
Range(Cells(1, 1), Cells(lastRow, 3)).Borders.LineStyle = xlContinuous
End Sub
ちょっとむずかしく見えますが、やっていることはシンプルです。Cells(Rows.Count, 1).End(xlUp).Row でA列の一番下から上に向かって最終行を探しています。
データの件数が増減しても自動で対応できるので、実務では非常に重宝します。最終行の取得方法をもっと詳しく知りたい方は「最終行を取得する3つの方法」もどうぞ。
もうひとつ、可変範囲をコピーする実例も見てみましょう。
Sub データ範囲をコピーして貼り付ける()
Dim lastRow As Long
Dim lastCol As Long
' データの最終行・最終列を取得
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
' データ範囲をまるごとコピー
Range(Cells(1, 1), Cells(lastRow, lastCol)).Copy
' Sheet2のA1に貼り付け
Sheets("Sheet2").Range("A1").PasteSpecial xlPasteValues
Application.CutCopyMode = False
End Sub
最終行だけでなく最終列も動的に取得すれば、列が増えても自動で対応できます。
実務シナリオ別の選択ガイド
ここまでの内容を、よくある実務シナリオで整理しましょう。
一覧表を上から順に処理する
請求書データや社員名簿を1行ずつ処理するパターンです。
Sub 一覧表を順に処理する()
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
Dim i As Long
For i = 2 To lastRow ' 2行目から(1行目はヘッダー)
' B列が空欄ならスキップ
If Cells(i, 2).Value <> "" Then
' D列に計算結果を入力
Cells(i, 4).Value = Cells(i, 2).Value * Cells(i, 3).Value
End If
Next i
End Sub
行を変数 i で動かすのでCells一択です。「For文」と「For Each」のどちらでもCellsが活躍します。条件分岐を入れたいときは「Do Loop」との組み合わせも検討してみてください。
可変範囲をまるごとコピーする
データの最終行・最終列が変わる範囲を一括操作するパターンです。
Sub 可変範囲を書式設定する()
Dim lastRow As Long
Dim lastCol As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
' データ範囲全体に背景色をつける
Range(Cells(2, 1), Cells(lastRow, lastCol)).Interior.Color = RGB(230, 240, 255)
End Sub
Range(Cells, Cells)の組み合わせが最適です。開始・終了を変数で制御しつつ、範囲全体をまとめて操作できます。
集計行をループの外に固定する
ヘッダーや集計行など、位置が固定のセルを操作するパターンです。
Sub 集計処理()
Dim lastRow As Long
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
' ループ部分はCells
Dim total As Long
Dim i As Long
For i = 2 To lastRow
total = total + Cells(i, 3).Value
Next i
' 固定セルへの書き込みはRange
Range("A1").Value = "集計結果"
Range("B1").Value = total
End Sub
ループ内はCells、固定セルはRangeと使い分けるのがスマートです。コードの意図が明確になり、後から読んでも何をしているか一目でわかります。
シナリオ別まとめ表
| シナリオ | おすすめ | 理由 |
|---|---|---|
| 一覧を上から順に処理 | Cells | 行番号を変数で動かす |
| 可変範囲を一括操作 | Range(Cells, Cells) | 動的な開始・終了を範囲指定 |
| 固定セルへの読み書き | Range | アドレス直書きで可読性が高い |
| 名前付き範囲の参照 | Range | Cellsでは名前定義を参照できない |
| 二重ループ(行×列) | Cells | 行列ともに数値で制御できる |
1004エラーの原因と対処法
RangeとCellsの組み合わせで最もハマりやすいのが、実行時エラー1004(「アプリケーション定義またはオブジェクト定義のエラー」)です。
Worksheetオブジェクトの明示
このエラーは、別シートのCellsをRange引数に渡すときに起きます。
' エラーになるコード
Sheets("Sheet2").Range(Cells(1, 1), Cells(10, 3)).Select
一見すると正しく見えますが、問題があります。Range は Sheet2 を指していますが、Cells はアクティブシートを指しています。シートの参照先がバラバラなのでエラーになるのです。
正しくはこう書きます。
' 正しいコード:Withでシートを統一する
With Sheets("Sheet2")
.Range(.Cells(1, 1), .Cells(10, 3)).Select
End With
ポイントは .Range と .Cells の先頭にドット(.)をつけることです。ドットをつけると、Withで指定したSheet2のプロパティとして認識されます。
ドットを1つでも忘れるとエラーになるので注意してください。
もうひとつ、シートを変数に入れて書く方法もあります。
' 変数でシートを指定する方法
Dim ws As Worksheet
Set ws = Sheets("Sheet2")
ws.Range(ws.Cells(1, 1), ws.Cells(10, 3)).Select
どちらの書き方でもOKです。大事なのは「Range・Cells・すべてのシート参照を揃える」ことです。
NOTE
1004エラーは実行時に発生するため、コードを書いた時点では気づけません。別シートを操作するコードを書いたら、必ずテスト実行して確認しましょう。
まとめ:迷ったときの使い分け早見表
RangeとCellsの使い分けを最終確認しましょう。
| やりたいこと | 使うもの | 書き方の例 |
|---|---|---|
| 固定セルに値を入れる | Range | Range("A1").Value = 100 |
| 名前付き範囲を参照 | Range | Range("売上合計").Value |
| ループで行を動かす | Cells | Cells(i, 1).Value |
| 行列ともに変数で動かす | Cells | Cells(r, c).Value |
| 動的範囲を一括操作 | Range + Cells | Range(Cells(1,1), Cells(lastRow,3)) |
| 別シートのセルを操作 | With + ドット付き | .Range(.Cells(1,1), .Cells(10,3)) |
判断に迷ったら、次の順番で考えてみてください。
- 名前付き範囲を使う? → Range
- セルの位置が固定? → Range
- 変数で位置を動かす? → Cells
- 動的な範囲指定? → Range(Cells, Cells)
どちらが正解ということではなく、場面で使い分けるのがベストです。VBAに慣れてくると自然とCellsを使う場面が増えてきます。
ぜひVBEを開いて、両方のコードを試してみてくださいね。
