和風スパゲティのレシピ

日本語でコーディングするExcelVBA

複数領域をセル範囲ごとに取得する - Areas

Range("A1,B2:C2,D4:E6")のような複数領域をもつRangeオブジェクトを、
各セル範囲ごとに分割して取得するAreasプロパティを解説します。

複数領域(Areas)をFor Eachでセル範囲ごとに取得する

RangeオブジェクトのAreasプロパティを使用すると、
Range内の複数セル範囲をひとつずつ分けて取り出すことができます。

Dim 親Range As Range
Set 親Range = Range("A1,B2:C2,D4:E6")

Dim 各セル範囲 As Range
For Each 各セル範囲 In 親Range.Areas
    Debug.Print 各セル範囲.Address
Next

このコードを実行すると、「$A$1」「$B$2:$C$2」「$D$4:$E$10」が表示され、
3つのRangeをエリアごとにループできていることが分かります。


対して、以下のコードのようにAreasをCellsに変えると、
「$A$1,$B$2,$C$2,・・・$E$6」と1セルずつのループになります。

For Each 各セル In 親Range.「Cells」

やりたい処理によってどちらのループにするかを選択してください。

Rangeオブジェクトが単一のセル範囲か判定する

Areasプロパティは「Count」プロパティを持つため、
Rangeオブジェクトがいくつの領域を持つかを調べることができます。

Rangeオブジェクトが単一のセル範囲かどうかを判定するには、
Areas.Countが1かどうかを判定します。

' Rangeが単一範囲の時にのみマクロを実行する
If 指定Range.Areas.Count = 1 Then
    ' ここに実行したい処理
End If

 

○番目のエリアを取得する

Areasプロパティの引数に数値を指定すると、
○番目のエリアを取得することができます。

例えば第1エリアだけを処理する場合は以下のコードを実行します。

' 第1エリアに対してだけ処理
Dim 処理Range As Range
Set 処理Range = 親Range.Areas(1)

処理Range.Value = 1

こちらのコードで個別のエリアを指定して処理できます。


エリア数を超える数値を指定すると、
「インデックスが有効範囲にありません。」
エラーとなりますのでご注意ください。


この仕様に先ほどのCountプロパティを組み合わせると、
For文でも全エリアをループするコードを書くことができます。

Dim 親Range As Range
Set 親Range = Range("A1,B2:C2,D4:E6")

Dim i As Long
Dim 各セル範囲 As Range
For i = 1 To 親Range.Areas.Count
    Set 各セル範囲 = 親Range.Areas(i)
    ' ここに各セル範囲への処理
Next

ただ全エリアを走査するだけならFor Each文で十分ですが、
エリア番号に関わるループを書く場合はこちらを使用してください。

Value、Rows、Columnsなどの仕様

Range("A1,B2:C2,D4:E6")などのRangeオブジェクトで注意が必要なのが、
Value、Rows、Columnsなどのプロパティの挙動です。

これらは「第1エリア」の状態を取得するよう動くため、
各結果は以下のようになります。

Dim 親Range As Range
Set 親Range = Range("A1,B2:C2,D4:E6")

親Range.Value ' ← A1セルの値が入ります。
親Range.Rows.Count ' ← 1
親Range.Columns.Count ' ← 1

 
つまりこれらのプロパティは、

親Range.Areas(1).Value ' ← A1セルの値が入ります。
親Range.Areas(1).Rows.Count ' ← 1
親Range.Areas(1).Columns.Count ' ← 1

このコードと同等に動くということになります。


逆に「総行数」をカウントするようなプロパティはありませんので、
これを実装する場合は愚直にカウントしていく必要があります。

Dim 親Range As Range
Set 親Range = Range("A1,B2:C2,D4:E6")

Dim 総行数 As Long: 総行数 = 0
Dim 各セル範囲 As Range
For Each 各セル範囲 In 親Range.Areas
    総行数 = 総行数 + 各セル範囲.Rows.Count
Next

複数領域を持つRangeオブジェクトを処理するときは、
この仕様に注意して使用してください。

おまけ:Areaオブジェクトはありません

Areasプロパティは「各Rangeオブジェクト」を取得するので、
返り値はRange型のプロパティです。

Areasコレクションの中にAreaオブジェクトがあるわけではありません。

' これはエラー(というかそもそも宣言できない)
Dim 各エリア As Area
For Each 各エリア In 親Range.Areas

一応このことも知っておいてください。