複数のセルを選択する


たとえば、条件に一致するセルを、次々と処理するのは簡単です。たとえば、選択したセル範囲内で、入力されている数値が100より大きかったら文字色を赤にするとします。次のようなコードで可能ですね。

Sub Sample1()
    Dim c As Range
    For Each c In Selection
        If c > 100 Then c.Font.ColorIndex = 3
    Next c
End Sub

これは簡単ですね。

では、条件に一致したセルを選択するには、どうしたらいいでしょう。

セルを選択するには、たとえば「Range("A1").Select」とします。連続していない複数のセルを選択するには「Range("A1,B2").Select」のように、セルのアドレスをカンマで区切って指定します。先のコードでは、条件に一致したセルをすぐ処理していますが、アドレスを「○○,△△,××,…」のような文字列に加工すれば、Rangeの中で指定できそうです。やってみましょう。

Sub Sample2()
    Dim c As Range, Target As String
    For Each c In Selection
        If c > 100 Then Target = Target & c.Address & ","
    Next c
    If Target = "" Then Exit Sub
    Target = Left(Target, Len(Target) - 1)    ''最後のカンマを消す
    Range(Target).Select
End Sub

うまくいきました。

ところがこのコード、思わぬバグを含んでいます。うまくいくときと、エラーになるときがあるんです。エラーになると、次のようなメッセージが表示されます。

「Rangeメソッドが失敗しました」って言われてもなぁ、失敗しないときだってあるし、何だよこれ、てゆーか失敗すんなよ、またバグかよ・・・みたいな。選択したセルの個数や、見つかったセルの個数を調べても、失敗との因果関係は明確になりません。これは、何が原因なのでしょう。

実は、変数Targetの文字数が255文字を超えるとエラーになります。セルを選択するRangeプロパティは、Range("A1")のようにセルのアドレス(またはセルに定義した名前)を文字列形式で指定します。このとき、指定できる文字列の長さは255文字までです。この制限はあまり知られていませんし、表示されるエラーメッセージにもそうした制限について書かれていませんから、エラーの原因がわからないで悩むユーザーも少なくありません。このエラーはアドレスを示す文字列の長さによりますので、マクロを実行する環境によってエラーが発生したりしなかったりと、原因を特定するのがやっかいなエラーです。

さて、255文字を超えるアドレスは指定できないのですから、何か別の手を使わなければなりません。こんなときは、複数セル範囲の集合を返すUnionメソッドを使います。

まず、Unionメソッドの動作を確認しましょう。次のコードは、セルA1とセルB3を選択します。

Sub Sample3()
    Union(Range("A1"), Range("B3")).Select
End Sub

したがって、For Each内で条件に一致したセル(制御変数c)を、次々とUnionメソッドで合体させてやればいいわけです。

Sub Sample4()
    Dim c As Range, Target As Range
    For Each c In Selection
        If c > 100 Then
            If Target Is Nothing Then    ''(1)
                Set Target = c
            Else
                Set Target = Union(Target, c)   ''(2)
            End If
        End If
    Next c
    If Not Target Is Nothing Then Target.Select     ''(3)
End Sub

条件に一致したセルは、Range型の変数Targetに格納します。すでに見つかったセルに、新しいセルを追加するのは(2)ですが、これだけだと1件目に見つかったセルの処理でエラーになります。1件目の処理では、変数Targetに、まだ何も格納されていないので「Union(Target, c)」が「Union(Nothing, c)」となってしまうからです。そこで、変数Targetが空かどうかを、(1)で判定しています。

最後に見つかったセル(変数Target)を選択するのですが、もし条件に一致するセルが1つもなかったとき、変数Targetは空のままです。何も格納されていない変数TargetをSelectするとエラーになりますので、(3)で、その判定をしています。

Unionメソッドは、決して使う機会の多いテクニックではありません。ただ、今回のようなケースでは、もしUnionメソッドを使わないと、かなり難しい処理になってしまいます。覚えておいて、損はないでしょう。