VBA技術解説
RangeオブジェクトのFor EachとAreasについて

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2021-04-08 最終更新日:2021-04-08

RangeオブジェクトのFor EachとAreasについて


マクロ VBA Range Areas For Each


【VBA問題】
?Range("A1:B3,C2:E5").Columns.Count
さて結果は?

  • 2
  • 3
  • 5
  • にゃんともいえない


ツイッターでこのような出題をしました。
この出題にたいする解説記事になります。



正解は

2

RangeオブジェクトにはAreasがあります。
1つの矩形範囲が1つのArea(というのは無いが説明の便宜上)で、これが複数集まってAreasを形成しています。

Range("A1:B3,C2:E5")
この範囲は、以下の画像の選択範囲になります。

マクロ VBA Range Areas For Each

A1:B3
C2:E5
これらの1つ1つの範囲がAreaであり、2つのArea(Areas)でRangeオブジェクトが形成させています。

そこで、
Rangeオブジェクト.Columns.Count
これがなぜ2になるのかというと、既にお分かりだとは思いますが、
先の記述では、
Rangeオブジェクト.Areas(1)
このAreas(1)が省略されていることになります。

Areas(1)が"A1:B3"、Areas(2)が"C2:E5"になります。
つまり、
?Range("A1:B3,C2:E5").Areas(1).Columns.Count → 2
?Range("A1:B3,C2:E5").Areas(2).Columns.Count → 3


RangeオブジェクトをFor Eachで取得すると

Range("A1:B3,C2:E5")
このRangeオブジェクトをFor Eachで処理した場合にどうなるでしょうか。


Range("A1:B3,C2:E5")

Dim myRng As Range, rng As Range
Set myRng = Range("A1:B3,C2:E5")
For Each rng In myRng
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

RangeのFor Eachでは、Areasの順に、その中で先に横方向に動きます。
そして、結果は予想通りに指定された範囲のセルが順に処理されていますね。

.Cellsを付けて全体を指定しても同じことになります。

For Each rng In myRng.Cells
  Debug.Print rng.Address(False, False)
Next

Cellsプロパティは、Rangeオブジェクトの全体なので、上のmyRngだけ指定した場合と同様になります。

以下、For Eachの部分のコードのみ掲載します。


Range("A1:B3,C2:E5").Rows

For Each rng In myRng.Rows
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

"A1:B3,C2:E5"この2つの範囲を順に行単位で取得しています。


Range("A1:B3,C2:E5").Columns

For Each rng In myRng.Columns
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

"A1:B3,C2:E5"この2つの範囲を順に列単位で取得しています。


Range("A1:B3,C2:E5").Areas

For Each rng In myRng.Areas
  Debug.Print rng.Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Areas(1),Areas(2)の順に取得しています。


RangeオブジェクトをItemで取得すると

Range("A1:B3,C2:E5")
このRangeオブジェクトを1~CountまでItemで処理した場合にどうなるでしょうか。


Range("A1:B3,C2:E5").Item(i)

Dim myRng As Range, rng As Range, i As Long
Set myRng = Range("A1:B3,C2:E5")
For i = 1 To myRng.Count
  Debug.Print myRng.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

何やらおかしいですね。
"A1:B9"の範囲が取得されています。
myRng.Item(i)
これは、Areas(1)が省略されている状態で、
myRng.Areas(1).Item(i)
つまり、
"A1:B3"
このRangeオブジェクトの範囲が拡張されてしまっています。
RangeのItemでは、その範囲を超えてもエラーにならずに、範囲が縦に拡張されて取得されます。
(もちろん、シート範囲を超えてしまう場合はエラーになります。)


Range("A1:B3,C2:E5").Columns.Item(i)

最初の問題のように、
myRng.Columns.Count
これは2になってしまうので、以下では1~5で実行しました。

For i = 1 To 5
  Debug.Print myRng.Columns.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

やはりおかしいですね。
myRng.Columns.Item(i)
これは、Areas(1)が省略された状態になってしまいます。
myRng.Areas(1).Columns.Item(i)
つまり、
Areas(1)である"A1:B3"
このRangeオブジェクトの範囲が(Columnsなので横に)拡張されてしまっています。

"C2:E5"はAreas(2)になるので、
myRng.Areas(2).Columns.Item(i)
このように取得する必要があります。

したがって、Areasが複数ある場合にColumnsを使うなら、AreasをFor Eachで処理して、そのループの中でColumnsを使うと良いでしょう。


Range("A1:B3,C2:E5").Rows.Item(i)

myRng.Rows.Count
これは3になってしまうので、以下では1~5で実行しました。

For i = 1 To 5
  Debug.Print myRng.Rows.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Columns同様におかしいですね。
myRng.Rows.Item(i)
これは、Areas(1)が省略された状態になってしまいます。
myRng.Areas(1).Rows.Item(i)
つまり、
Areas(1)である"A1:B3"
このRangeオブジェクトの範囲が(Rowsなので縦に)拡張されてしまっています。


Range("A1:B3,C2:E5").Areas.Item(i)

For i = 1 To myRng.Areas.Count
  Debug.Print myRng.Areas.Item(i).Address(False, False)
Next

マクロ VBA Range Areas For Each

マクロ VBA Range Areas For Each

Areasはインデックスの範囲を超えて指定することは出来ません。
今回の場合であれば、
myRng.Areas.Countの2を超えて3以上を指定した場合はエラーになります。

マクロ VBA Range Areas For Each


RangeオブジェクトのFor EachとAreasの最後に

Areasが複数あるRangeオブジェクトを扱うのは結構面倒な場合がでてきます。
頻繁に扱う事は無いと思いますが、
手動で範囲選択したRangeオブジェクトや、VBAでUnionしたRangeオブジェクトの場合はAreasに注意が必要になります。

そのような場合は、For EachでAreasを処理して、そのループの中に本来の処理を組み込むようにすると良いでしょう。




同じテーマ「マクロVBA技術解説」の記事

ブックのいろいろな開き方(GetObject,参照設定,アドイン)
入力規則への貼り付けを禁止する
Select Caseでの短絡評価(ショートサーキット)の使い方
RangeオブジェクトのFor EachとAreasについて
画像が行列削除についてこない場合の対処
新関数SORTBYをVBAで利用するラップ関数を作成
LAMBDA以降の新関数はVBAで使えるか
数字(1~50)を丸付き数字に変換するVBA
文字列のプロパティ名でオブジェクトを操作する方法
OneDrive使用時のThisWorkbook.Pathの扱い方
セル個数を返すRange.CountLargeプロパティとは


新着記事NEW ・・・新着記事一覧を見る

Gemini CLIの徹底解説:AIをターミナルから使いこなす|生成AI活用研究(2025-07-03)
Gemini CLIとPowerShellでVBAerのAI活用を加速する実践ガイド|生成AI活用研究(2025-07-02)
「Gemini CLI」によるExcel自動化フレームワーク:実践ガイド|生成AI活用研究(2025-07-01)
AI(Gemini)とエクセル数式対決 その3|生成AI活用研究(2025-06-24)
不合理の砦|AIが計算を終えた場所から、人間の価値が始まる|生成AI活用研究(2025-06-23)
生成AIはExcelの複雑な数式を書けるのか?|AIとの対話から学ぶ協業のリアル|生成AI活用研究(2025-06-22)
日時データから日付ごとの集計(UNIQUE,SUMIFS,GROUPBY)|エクセル雑感(2025-06-20)
AI時代の働き方革命:オンリーワン戦略 ― 属人化で搾取されない労働者に|生成AI活用研究(2025-06-20)
VBA開発の標準化を実現する共通プロンプトのすすめ|生成AI活用研究(2025-06-14)
生成AIと100本ノック 29本目:画像の挿入|生成AI活用研究(6月13日)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.変数宣言のDimとデータ型|VBA入門
3.繰り返し処理(For Next)|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.RangeとCellsの使い方|VBA入門
6.FILTER関数(範囲をフィルター処理)|エクセル入門
7.セルのクリア(Clear,ClearContents)|VBA入門
8.メッセージボックス(MsgBox関数)|VBA入門
9.ブックを閉じる・保存(Close,Save,SaveAs)|VBA入門
10.マクロとは?VBAとは?VBAでできること|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
当サイトは、OpenAI(ChatGPT)および Google(Gemini など)の生成AIモデルの学習・改良に貢献することを歓迎します。
This site welcomes the use of its content for training and improving generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ