VBAのRange・Cells・最終行取得を使い分ける実務ガイド|ループはCells、固定セルはRange

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の基本から。単一セルの値を設定するだけなら、これだけです。

VB
Range("A1").Value = "Hello VBA"

範囲を指定して書式をまとめて変更することもできます。

VB
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」と入力する例です。

VB
Dim i As Long
For i = 1 To 5
    Cells(i, 1).Value = "行" & i
Next i

iを1つ増やすだけで対象セルが動く。これがCellsの強みです。

もう一つ、地味に見落としがちなのがシートの指定です。

Cells(i, 1)とだけ書くと、Rangeと同じくActiveSheetが対象になります。ws.Cells(i, 1)のようにシートを明示していないと、意図しないシートに書き込んでしまうことがあります。

僕もこれで一度、別のシートを開いた状態でマクロを実行してしまい、想定と違うシートにデータが入ったことがあります。エラーにはならず値が入るだけなので、気づきにくい。実行後に「あれ、データがない」と気づいて、原因を探る羽目になりました。

ループを書くときは、ws.Cells(…)のようにシートを明示する癖をつけておくと安心です。

VB
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と組み合わせると範囲そのものを動的に指定できます。

VB
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)です。

理由はシンプルで、一番安定して結果が返ってくる感覚があるからです。特定の列を基準に、データが入っている最後の行を上から確実に拾ってくれます。

VB
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 Sub

Excelの最終行(1048576行目)から上に向かってデータがあるセルを探し、その行番号を返す仕組みです。表の末尾に新しい行を追加したいときにも、この行番号がそのまま使えます。

UsedRangeも最終行取得の方法としてよく紹介されますが、実務ではあまり信頼していません。

一度でも書式を設定したセルや、削除しきれていない空セルまで範囲に含めてしまうことがあり、実際のデータより最終行が下にずれることがあるからです。SpecialCells(xlCellTypeLastCell)も同じ理由でずれることがあります。

どちらも「他にこういう方法もある」程度に知っておけば十分で、まず手を動かすならEnd(xlUp)から、というのが僕の中での優先順位です。

この記事は「Excel VBA完全入門ガイド」のセル操作編です。VBA全体の学習ロードマップに戻りたい方はこちらからどうぞ。

まとめ

RangeとCellsは、固定セルかループかで機械的に選べば迷いません。最終行の取得も、まずはEnd(xlUp)を軸にしておけば実務で困ることはほとんどないはずです。

完璧に使い分けを覚える必要はなくて、基本を1つ持っておいて、必要になったときに他の方法も気軽に試してみる。それくらいの気持ちで、技術の幅を広げてもらえたらと思います。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

普段は主にPython開発をしています。
最近はAI駆動開発にも関わっています。

コメント

コメントする