VBAでセルを操作するとき、最初はだいたいRangeを使います。
Range(“A1”)のように書けば、見たままセルを指定できるので直感的です。
ところが、ループで行を動かしながら処理しようとした瞬間に困ります。文字列のセル番地を、for文の中でどう組み立てればいいのか迷うからです。
そこで使うのがCellsです。
Cellsは行・列を数字で指定できるので、ループとの相性が抜群です。
僕も実務では、ループを書くときはほぼ必ずCellsを使っています。固定のセルを1つ触るだけならRangeで十分ですが、行を動かしながら処理するとなると、Cellsの方が圧倒的に書きやすいからです。
この記事では、RangeとCellsの使い分け方から、地味につまずきやすいポイント、そして意外と重要な最終行の取得方法まで、実務でよく使う形に絞って解説します。
RangeとCellsはどう使い分ければいいのか
結論から言うと、判断基準はシンプルです。
固定のセルを触るならRange、ループで動かすならCells。これだけ覚えておけば、実務のほとんどのケースはカバーできます。
| やりたいこと | 使うもの |
|---|---|
| A1など決まったセルを操作する | Range |
| 行・列を変数で動かしながら処理する | Cells |
なぜCellsがループ向きなのかというと、行番号・列番号のどちらも数字で扱えるからです。
Range(“A1”)のような文字列をループのたびに組み立て直すのは面倒ですし、バグの元にもなります。Cells(i, 1)なら、iを増やすだけで済みます。
Rangeの基本操作
まずはRangeの基本から。単一セルの値を設定するだけなら、これだけです。
Range("A1").Value = "Hello VBA"範囲を指定して書式をまとめて変更することもできます。
Range("A1:B2").Interior.Color = RGB(255, 255, 0)A1からB2までの背景色が黄色になります。決まったセル・決まった範囲を触るだけなら、Rangeの読みやすさに勝るものはありません。
Cellsの引数、実は最初はわかりにくい
Cellsの引数は、Cells(行, 列)の順番です。
正直に言うと、僕は最初これを見たとき「あれ、行が先だっけ、列が先だっけ」となりました。
Range(“A1”)なら見たままなのに対して、Cells(1, 1)は数字が並んでいるだけなので、パッと見て対応関係がわかりにくいんですよね。じっくり見ればCells(行, 列)だとわかるんですが、初見だとRangeほど直感的ではありません。
次のコードは、A列に1行目から5行目まで「行1」〜「行5」と入力する例です。
Dim i As Long
For i = 1 To 5
Cells(i, 1).Value = "行" & i
Next iiを1つ増やすだけで対象セルが動く。これがCellsの強みです。
もう一つ、地味に見落としがちなのがシートの指定です。
Cells(i, 1)とだけ書くと、Rangeと同じくActiveSheetが対象になります。ws.Cells(i, 1)のようにシートを明示していないと、意図しないシートに書き込んでしまうことがあります。
僕もこれで一度、別のシートを開いた状態でマクロを実行してしまい、想定と違うシートにデータが入ったことがあります。エラーにはならず値が入るだけなので、気づきにくい。実行後に「あれ、データがない」と気づいて、原因を探る羽目になりました。
ループを書くときは、ws.Cells(…)のようにシートを明示する癖をつけておくと安心です。
Sub HighlightHighValues()
Dim ws As Worksheet
Dim i As Long
Set ws = ThisWorkbook.Sheets("Sheet1")
For i = 2 To 20 ' 2行目以降のE列を対象
If ws.Cells(i, 5).Value > 100000 Then
ws.Cells(i, 5).Interior.Color = RGB(255, 230, 230)
End If
Next i
End Sub売上が一定値を超えた行だけ背景色を変える例です。シートを明示しているので、どのシートに対して実行しても安心です。
RangeとCellsを組み合わせて範囲を動的に指定する
Cellsは1つのセルを指す書き方ですが、Rangeと組み合わせると範囲そのものを動的に指定できます。
Sub DynamicRangeWithCells()
Dim startRow As Long: startRow = 2
Dim endRow As Long: endRow = 10
' A2:A10 に「OK」と入力
Range(Cells(startRow, 1), Cells(endRow, 1)).Value = "OK"
End Sub開始行・終了行を変数で持っておけば、データ件数が変わっても同じコードで対応できます。件数が実行のたびに変わる集計処理などで重宝する書き方です。
最終行の取得は、まずEnd(xlUp)で困らない
最終行を取得する方法はいくつか紹介されていますが、実務でまず選ぶのはEnd(xlUp)です。
理由はシンプルで、一番安定して結果が返ってくる感覚があるからです。特定の列を基準に、データが入っている最後の行を上から確実に拾ってくれます。
Sub GetLastRow()
Dim ws As Worksheet
Dim lastRow As Long
Set ws = ThisWorkbook.Sheets("データ")
lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
MsgBox "A列の最終行は: " & lastRow & " 行目です"
End SubExcelの最終行(1048576行目)から上に向かってデータがあるセルを探し、その行番号を返す仕組みです。表の末尾に新しい行を追加したいときにも、この行番号がそのまま使えます。
UsedRangeも最終行取得の方法としてよく紹介されますが、実務ではあまり信頼していません。
一度でも書式を設定したセルや、削除しきれていない空セルまで範囲に含めてしまうことがあり、実際のデータより最終行が下にずれることがあるからです。SpecialCells(xlCellTypeLastCell)も同じ理由でずれることがあります。
どちらも「他にこういう方法もある」程度に知っておけば十分で、まず手を動かすならEnd(xlUp)から、というのが僕の中での優先順位です。
この記事は「Excel VBA完全入門ガイド」のセル操作編です。VBA全体の学習ロードマップに戻りたい方はこちらからどうぞ。

まとめ
RangeとCellsは、固定セルかループかで機械的に選べば迷いません。最終行の取得も、まずはEnd(xlUp)を軸にしておけば実務で困ることはほとんどないはずです。
完璧に使い分けを覚える必要はなくて、基本を1つ持っておいて、必要になったときに他の方法も気軽に試してみる。それくらいの気持ちで、技術の幅を広げてもらえたらと思います。

コメント