siyoudekimasen’s blog

カオスとバグの人

【VBA】~結合セルのアドレス指定~

どうも、Bugです。 前回の記事に使用したセル結合のアドレス範囲について説明したいと思います。 どうせ、次に書くときは自分も忘れているし

※結合セルのアドレス範囲指定は、レイアウト依存になりますので非推奨です。 個人的には、推奨Lv20くらい上の力が必要になるイメージでいます。 直せるなら、データやロジックから結合セルとアドレスをなくす方が吉です。

データ>>ロジック>>>>(絶望の淵)>>結合セルのアドレス範囲指定

前回の記事

buggaiqai.hatenablog.com

結合セルのアドレス取得

まず、アドレスを取得する場合、VBAでは基本Range.Addressを使いますよね。

f:id:siyoudekimasen:20210504015649j:plain
結合セルのアドレス取得
B2:D4のセルが結合セルとした場合、
単独セルをSetされている場合、Range.Addressは単一範囲で帰ってくる。
(Range("B2").address = $B$2)
複数セルをSetされている場合、Range.Addressは複数範囲で帰ってくる。
(Range("B2:D4").address = $B$2:$D$4)

あ~なるほど、挙動的にはわかるよね。……いや怖いんだけど
プログラムの書き手は、処理のRangeの返り値が先頭で返しているか、範囲で返しているか認識しなきゃいけないの?
それは、めんどい。どっちかに合わせたい。明示的に分岐したい。

単一範囲で統一するなら
Range("B2:D4").Offset(0,0).address = $B$2
複数範囲で統一するなら
Range(単一セル).MergeArea.Address = $B$2:$D$4

とするのが楽な気がする。
個人的には単一範囲の方が扱いやすい。だって複数セルだとMergeArea異常起こすし……

Offsetの選択範囲

前回の記事では用いられている結合セルでのOffsetの仕様について触れていこうと思います。
(注1)たしか作成時に、Offsetの仕様についてdocsにも書いてあった気がするんだけど、見つからない。
どなたか知っている人がいらっしゃったら教えてください。

前回の処理では、結合セルにテキストをコピペするという仕様上、
結合セルから結合セルに移動する必要があります。
他の例だと、『結合されているヘッダー行で判定してから、処理をする』みたいなパターンもあり得ますね。

というわけで、ここでOffsetが出てくるわけですけど、
↓同じタイミングで、Offsetの指定位置だけ変えて実行してみます。

f:id:siyoudekimasen:20210504013212j:plain
結合セルのOffsetの選択先範囲

こんな感じで、Offset(1,0)とOffset(2,0)の選択範囲は直感と反するような振る舞いをします。
というよりも、Offsetの仕様として起点セルの外枠に出るときだけ、結合セルとして扱うというような動きをしているようにみえます。
(ここの仕様がdocsのどこかに記述されている気がするんだけど、記載箇所わからない。どなたか教えてください。)

逆に言えば、結合セルが連続的・構造的であるなら
結合セルの起点をSetで取り直して、Offset(1,0)やOffset(0,1)で移動する方法もありかも

注釈

和風スパゲティさんの記事にOffsetについてより詳しい情報があった。 www.limecode.jp -1とかで戻るパターンもあるか~~。想定が足りてなかった。

f:id:siyoudekimasen:20210504030540j:plain
戻るパターンで先頭セルを取得する
先頭セルはとれなくはない。…とれなくはないけど、普段からそんなアクロバティックなコードの書き方したくない。