Excel VBA | セル範囲取得(Endプロパティ)

VBA
スポンサーリンク

1. まず結論(何ができるの?)

Excel VBA の Range.End プロパティを使うと、あるセルから見て値が入っている「最後のセル」(下・上・右・左いずれか)を簡単に取得できます。
実務でよく使うのは「データの最終行」「最終列」を自動で見つけること —— データの量が変わってもマクロを壊さずに処理できます。


2. Range.End の基本イメージ(図を頭に描いて)

  • Range("A1").End(xlDown)
    → A1 から下に向かって「連続しているセル」をたどり、空白に出会う直前(もしくはブロックの最後)のセルを返す。
  • 方向は xlDown, xlUp, xlToRight, xlToLeft の 4種類。

重要な直感End は Excel のキーボード操作の Ctrl + ↓(あるいは Ctrl + →)と同じ動作をします。


3. なぜ注意が必要か(典型的な落とし穴)

Range.End は「途中に空白セルがあるとそこで止まる」ので、表の途中に空白行や空白列があると期待した最終行を返さないことがあります。

例:A列にデータがあって途中で空白があると、Range("A1").End(xlDown) は空白の直前で止まる → 本当の最終行がもっと下にあっても見つけられない。


4. 実務でよく使う安全で安定したパターン

a) 列に対する最終行(もっともポピュラー)

Dim lastRow As Long
lastRow = Cells(Rows.Count, "A").End(xlUp).Row
VB

解説

  • Rows.Count はワークシートの最終行番号(Excel 2010以降は 1048576)を返す。
  • その一番下(Cells(Rows.Count, "A"))から xlUp(上方向)へ探すと、途中の空白に影響されずにその列で最後に値が入っている行が取得できます。

b) 行に対する最終列

Dim lastCol As Long
lastCol = Cells(1, Columns.Count).End(xlToLeft).Column
VB

解説:行1の右端から左に探すパターン。列数を右端(Columns.Count)から探すので、途中の空白列に影響されにくい。


c) シート全体の最終セル(より堅牢に)

Dim lastCell As Range
Set lastCell = ActiveSheet.Cells.Find(What:="*", _
    After:=ActiveSheet.Cells(1,1), _
    LookIn:=xlFormulas, _
    LookAt:=xlPart, _
    SearchOrder:=xlByRows, _
    SearchDirection:=xlPrevious)
If Not lastCell Is Nothing Then
    Debug.Print "最終使用セルは: " & lastCell.Address
End If
VB

解説

  • Cells.Find を使うと、シート全体で最後に使われているセル(値や数式が入っているセル)を確実に見つけられます。
  • SearchDirection:=xlPreviousSearchOrder:=xlByRows がポイント。

5. 実際に動く「よくある例題」を3つ(コピペして使える)

例題A:A列の最終行を取得して、その範囲をメッセージ表示

Sub ExampleA()
    Dim lastRow As Long
    lastRow = Cells(Rows.Count, "A").End(xlUp).Row
    MsgBox "A列の最終行は " & lastRow & " 行目です。"
End Sub
VB

例題B:ヘッダ(1行目)を除くデータを別シートにコピー

Sub CopyDataExcludingHeader()
    Dim wsSrc As Worksheet, wsDst As Worksheet
    Dim lastRow As Long, lastCol As Long
    
    Set wsSrc = ThisWorkbook.Worksheets("Sheet1")
    Set wsDst = ThisWorkbook.Worksheets("Sheet2")
    
    lastRow = wsSrc.Cells(wsSrc.Rows.Count, "A").End(xlUp).Row
    lastCol = wsSrc.Cells(1, wsSrc.Columns.Count).End(xlToLeft).Column
    
    If lastRow < 2 Then
        MsgBox "データがありません(ヘッダのみ)"
        Exit Sub
    End If
    
    wsSrc.Range(wsSrc.Cells(2, 1), wsSrc.Cells(lastRow, lastCol)).Copy _
        Destination:=wsDst.Cells(1, 1)
    
    MsgBox "コピー完了: " & lastRow - 1 & " 行をコピーしました。"
End Sub
VB

ポイント:ヘッダ行(1行目)を除いたデータだけをコピーしたい場合、データの開始行を 2 にする。

例題C:最後の行までループして合計を計算(A列の合計)

Sub SumColumnA()
    Dim lastRow As Long
    Dim i As Long
    Dim total As Double
    
    lastRow = Cells(Rows.Count, "A").End(xlUp).Row
    total = 0
    
    For i = 1 To lastRow
        If IsNumeric(Cells(i, "A").Value) Then
            total = total + Cells(i, "A").Value
        End If
    Next i
    
    MsgBox "A列の合計 = " & total
End Sub
VB

ワンポイント:値のタイプをチェックする IsNumeric を入れると安全。


6. よくある応用パターン(テンプレ)

  • 動的範囲を Range(Cells(1,1), Cells(lastRow, lastCol)) で作り、その範囲を一括で処理(コピー・集計・書式変更など)。
  • 大量データを扱うなら、セルごとの処理を避けて 配列に読み込んで処理 → 結果を一括で書き戻す(速度が格段に上がる)。

7. さらに堅牢にする小さな工夫

  • 「列に全くデータがない(空列)」のケースを考える:
If WorksheetFunction.CountA(Columns("A")) = 0 Then
    MsgBox "A列は空です"
Else
    lastRow = Cells(Rows.Count, "A").End(xlUp).Row
End If
VB
  • UsedRange も使えるが、ユーザー操作でゴミ(表示上は空でも使用履歴が残るセル)があると最終セルが大きく誤差を出すことがある。Find("*", ...) の方が実務では信頼性が高い。

8. 練習問題

問題1(初級)
Sheet1 の B列にデータがある。最終行を取得して、最終行の下に「END」と書き込むマクロを書きなさい。

解答(模範)

Sub Practice1()
    Dim lr As Long
    lr = Cells(Rows.Count, "B").End(xlUp).Row
    Cells(lr + 1, "B").Value = "END"
End Sub
VB

問題2(中級)
Sheet1 のデータ(1行目はヘッダ)を Sheet2 に同じ列幅でコピーするマクロを書きなさい。データの最終行・最終列は動的に検出すること。

解答(模範)

Sub Practice2()
    Dim ws1 As Worksheet, ws2 As Worksheet
    Dim lr As Long, lc As Long
    Set ws1 = Worksheets("Sheet1")
    Set ws2 = Worksheets("Sheet2")
    
    lr = ws1.Cells(ws1.Rows.Count, 1).End(xlUp).Row
    lc = ws1.Cells(1, ws1.Columns.Count).End(xlToLeft).Column
    
    ws1.Range(ws1.Cells(1, 1), ws1.Cells(lr, lc)).Copy Destination:=ws2.Cells(1, 1)
End Sub
VB

まとめ(初心者が覚えるべき3つ)

  1. Range.End は便利だが 途中空白に弱い → 列の最終行は下端から xlUp で探すのが安定。
  2. シート全体の最後を確実に知りたいときは Cells.Find(What:="*", ... SearchDirection:=xlPrevious) を使う。
  3. 大量行を扱うなら、1セルずつ処理するより配列で一括処理する方が速い(これは次のステップで学ぶと良い)。

VBA
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました