RangeとCells

Rangeというのは日本語では“範囲”のことを言う。
シート内のどこからどこまで、という表記になる。
もちろん1つのセルでも構わない。「A1〜A1という範囲」も、論理的には間違いではない。
一方Cellsが示すものはあくまでひとつのセルである。

1つ重要な事は、Rangeはオブジェクトであり、Cellsはプロパティである、ということ。
そもそも同列に考えること自体が間違っている。
CellsというのはRange(というオブジェクト)の中のひとつのセルを表わすもの(プロパティ)と考えると理解が深まるのではないだろうか。
Rangeがなくて単にCells(1,1)とも書けるじゃないか、という方もおられると思うが、その場合は暗黙的にシート全体がRangeとなると考えれば良いだろう。
言うまでもなく、シート全体で見ればCells(1,1)はA1と同じになる。

「Rangeはオブジェクト、Cellsはプロパティ」の違いがわかりやすい例としては
Dim r as Range
Set r = Range("C5:D20")
Debug.Print r.Cells(1,1)
のような記述ができる。
RangeとCellsをごっちゃに考えていると違和感があると思う。
これでprintされるのは"A1"の値ではなくて"C5"の値である。
C5〜D20の範囲(世界)で考えてセル座標(1,1)はセルC5であり、その値を表示する、と解釈される。

Excelのシート上にある表は必ずしも左上隅から始まるとは限らない。
ズレていると処理の開始行は6だから変数の開始を6にして、とかになる。
デバッグの時も判りづらいし、その表を移動したりすればまた面倒だ。
こういうとき、その表をRangeで設定しておき、処理を.Cells(x,x)で行ういう方針で行えば、どこに表が置かれていても、プログラムとしては表は左上隅(1,1)から始まるとして書くことができる。
この方針で作れば、表を移動させても最初のRange設定をいじるだけで良く、処理部分に手をつける必要性が低くなる。
(最も推奨されるのは“テーブル”を使うことだろうが、大袈裟に感じる事も多いし、テーブル機能自体が“見出し行”(VBAではHeader)が一行しか許されないので現実として使い勝手も悪い)

また、この考え方で便利なのは“セル結合”されたシートを扱うときだろう。
例えばA1からA5が結合されており、“北海道”という値が入っているとする。
この時、その値が入っているのはA1のみであり、A2〜A5は空である。
このような“仕様”がVBAの処理で困ったことになることは多い。
表作成者としては1〜5行目までは“北海道”のナニカという意図なのだろうが、VBAで単純にRangeやCellでA2〜A5の値を引用しようとしても空の値しか返ってこないからだ。

このような時にはMergeAreaというRangeオブジェクトの一種を利用すると良い。
例えばRange("A1").MergeAreaはRange("A1:A5")と同じ意味を持つ。
Range("A2").MergeAreaもRange("A3").MergeAreaも、はたまたA4やA5の場合でも同じになる。
つまり結合されたどのセルを指しても、結合された全体のRangeを得ることができて、VBAのプログラムとしては都合が良い。

そしてこの範囲のいずれかを指定して期待される値は、一番左上隅つまりCells(1,1)が持っている。
よってsにはA1,A2,A3,A4,A5のいずれかが入っているとして
Range(s).MergeArea.Cells(1,1)
とすればよい。
つまりこれで結合されたどのセルを指しても“北海道”という期待通りの値を得ることできる。
-