🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の SpecialCells — 空白・可視セル・定数を選択する(そして 1 つも見つからないとエラーになる理由)

|

Excel VBA の SpecialCells — 空白・可視セル・定数を選択する(そして 1 つも見つからないとエラーになる理由)

TL;DRSpecialCells は、アドレスではなく種類でセルを選ばせます。すべての空白、 すべての可視セル、すべての数式、すべての定数 — これらを Excel が拾います。ホーム → 検索と選択 → 条件を選択してジャンプのコード版です。最も大事なルール:1 つも 見つからないとき、空の範囲は返らず、**error 1004「セルが見つかりません」**が発生します。 だから無防備な呼び出しは時限爆弾です。必ずこう包みます:

Dim blanks As Range
On Error Resume Next
Set blanks = ThisWorkbook.Worksheets("Data").Range("A2:A1000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not blanks Is Nothing Then blanks.Value = 0   ' 空白が実際に見つかったときだけ走る

ここまでで組み立ててきた参照は、どれも1 つの長方形を表していました — Range("A1:D100")Cells(r, c)ResizeCurrentRegion で切り出したブロック。しかし実務が欲しがるのは、 長方形とは限りません。埋めるべきすべての空セル、フィルター後の可視行だけ、ロックしたい 数式だけSpecialCells は、それを頼むための道具です — アドレスを述べるのをやめ、どんな 種類のセルが欲しいかを述べ始めます。本記事は 1 つの考えを軸にしています。SpecialCells は参照を返すフィルターであり、「該当なし」は空集合ではなくエラーだ。 これを押さえれば、 ほかの罠はすべて消えます。

この記事で学べること

  • 考え方の軸 — SpecialCells種類でセルを選ぶ、条件を選択してジャンプのコード版
  • 最も大事なルール — 該当がないと error 1004 を投げるので、あらゆる呼び出しをガードする
  • 実際に使うセルの種類 — 空白、可視、定数、数式、最後のセル
  • 空白埋めパターン — xlCellTypeBlanks と 1 行の数式
  • 可視行コピーパターン — AutoFilter のあとの xlCellTypeVisible(行数を守る切り札)
  • 結果がしばしば非連続(複数の Areas)になる理由と、それが変えること

考え方の軸:SpecialCells は種類でセルを選ぶ、アドレスではなく

RangeCells は、どのセルかに位置 — 文字列か 2 つの数値 — で答えます。SpecialCells は別の問いに答えます。ある種類のセルはどれか? 検索する領域と種類の定数を渡すと、Excel は その領域を走査し、条件に合うすべてのセルへの参照を返します。

Dim used As Range: Set used = ActiveSheet.UsedRange
used.SpecialCells(xlCellTypeFormulas).Interior.Color = vbYellow   ' すべての数式を強調する

条件を選択してジャンプF5 を押してセル選択)を使ったことがあれば、これはまさに あのダイアログのコード版です — 「定数」「数式」「空白セル」「可視セル」は同じ選択肢です。 強みは、走査を Excel がやってくれること。「これは空白か?」とシートをループで尋ねることは 一切なく、すべての空白を一度に頼み、Excel が 1 つの(しばしば奇妙な形の)範囲として返します。

最も大事なルール:該当がないとエラーになる

動くマクロをクラッシュに変えるのが、この一点です。検索領域の中で種類に合うセルが1 つも ないとき、SpecialCells は空の範囲を返しませんerror 1004「セルが見つかりません」 を発生させます。空白がゼロの範囲を SpecialCells(xlCellTypeBlanks) に通すと、マクロはそこで 止まります。

' 脆い書き方 - 空白が 1 つもない日に error 1004 でクラッシュする:
Range("A2:A1000").SpecialCells(xlCellTypeBlanks).Value = 0

これはバグではなく仕様です。SpecialCells は「該当なし」を空集合ではなく例外的な状態として 扱います。つまり安全な書き方は任意ではなく、唯一の正しい書き方です。3 段構えのガードは、 エラー処理を有効にし、呼び出しを実行し、すぐ無効に戻し、それから Nothing を判定します。

Dim hits As Range
On Error Resume Next
Set hits = Range("A2:A1000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0                       ' 直ちに通常のエラー報告へ戻す
If hits Is Nothing Then
    MsgBox "No blank cells to fill."
Else
    hits.Value = 0
End If

On Error Resume Next は危険な 1 行だけを覆い、On Error GoTo 0 がその直後に通常のエラー 報告を戻すので、ほかのバグを黙って握りつぶすことはありません(VBA On Error を参照)。ガードを省けば、マクロは時限爆弾になります — 空白のあるテスト用ファイルでは すべて動き、最初のきれいなファイルで爆発します。

実際に使うセルの種類

SpecialCells(Type, [Value]) は種類の定数を取り、ほんの一握りでほぼすべてを賄えます。

rng.SpecialCells(xlCellTypeBlanks)         ' 領域内の空セル
rng.SpecialCells(xlCellTypeVisible)        ' フィルターや非表示行で隠れていないセル
rng.SpecialCells(xlCellTypeConstants)      ' 直接入力した値(数値、文字列) - 数式ではない
rng.SpecialCells(xlCellTypeFormulas)       ' 数式を持つセル
rng.Cells.SpecialCells(xlCellTypeLastCell) ' 使用範囲の右下の角

xlCellTypeConstantsxlCellTypeFormulas は、結果の型で絞る任意の第 2 引数を取ります — SpecialCells(xlCellTypeFormulas, xlErrors) は、いまエラーを返している数式だけをつかむので、 シート上のすべての #REF!#DIV/0! を見つける最速の方法です。

Dim bad As Range
On Error Resume Next
Set bad = ActiveSheet.Cells.SpecialCells(xlCellTypeFormulas, xlErrors)
On Error GoTo 0
If Not bad Is Nothing Then bad.Interior.Color = vbRed   ' エラー数式を一度にすべて印づける

空白埋めパターン

SpecialCells に手を伸ばす定番の理由は、レポートの隙間を埋めること — 下に続く空白へラベルを 繰り返す、空の数値をゼロにする、です。空白を選び、選択全体へ一気に書き込みます。各空白の のセルの値をコピーするには、相対 R1C1 数式を使ってから値に変換します。

Dim gaps As Range
On Error Resume Next
Set gaps = Range("A2:A5000").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not gaps Is Nothing Then
    gaps.FormulaR1C1 = "=R[-1]C"      ' 各空白 = 真上のセル
    gaps.Value = gaps.Value          ' 数式を静的な値に固定する
End If

これは数千の隙間をループなしの 2 行で埋めます。FormulaR1C1 = "=R[-1]C" は「1 行上、同じ列」 を意味し、すべての空白へ一度に書き込まれます。2 行目は数式を結果に置き換えるので、並べ替えても 埋めた値が残ります。

可視行コピーパターン(行数を守る切り札)

xlCellTypeVisible は最も役立つ種類です。なぜなら、それなしで VBA がすることのせいです。 AutoFilter を適用したあと、フィルターで外れた行は消えたのではなく 隠れているだけ — そして素の .Copy はそれらもコピーします。ユーザーに見えているものだけを 操作するには、SpecialCells(xlCellTypeVisible) を経由しなければなりません。

' フィルターが残した可視行だけをコピー - 隠れた行は飛ばす:
ws.Range("A1").CurrentRegion.SpecialCells(xlCellTypeVisible).Copy _
    Destination:=Sheets("Summary").Range("A1")

xlCellTypeVisible がないと、これはブロック全体を隠れた行ごとコピーし、ユーザーがフィルターで 除いたデータを黙って貼り付けます。これはアドレス指定のクラスターと本物のフィルター作業とを つなぐ橋です。CurrentRegion がブロックを見つけ、SpecialCells(xlCellTypeVisible) がそれを 可視行に絞ります。同じ発想でフィルター済みの行を削除できます。フィルターしてから .Offset(1).SpecialCells(xlCellTypeVisible).EntireRow.Delete です。

複数エリアの落とし穴:結果はしばしば長方形ではない

SpecialCells を、それ以前のどの参照とも違うものにしているのがこれです。返る範囲はたいてい 非連続です。散らばった 10 個の空白は、10 個の別々のエリアから成る 1 つの参照として 返ります。それは調べ方を変えます。

Dim vis As Range: Set vis = rng.SpecialCells(xlCellTypeVisible)
Debug.Print vis.Count            ' すべてのエリアを合わせた可視セルの総数
Debug.Print vis.Areas.Count      ' それがいくつの別ブロックか
Dim a As Range
For Each a In vis.Areas
    Debug.Print a.Address        ' 連続する各ブロックを 1 つずつ
Next a

.Count はセルの総計、.Areas.Count はそれらが成す分離ブロックの数です。ほとんどの操作 — 値の設定、色づけ、別シートへの .Copy — はすべてのエリアを一度に扱うので、ループはめったに 要りません。例外は順序に依存するものです。SpecialCells で見つけた行を削除するなら、上へ 向かってループするのではなく .EntireRow を 1 回の呼び出しで削除しましょう。エリアが下から上 の順である保証はないからです。この複数エリアの形は Union と共通で、 Union は同じ非連続の参照を意図して組み立てます。

ExcelMaster の活用

SpecialCells が強力なのは、まさに鋭いからです。On Error のガードを忘れればきれいな ファイルがマクロをクラッシュさせ、xlCellTypeVisible を忘れればフィルターが隠していた行を コピーし、結果を長方形と思い込めばセルごとのループが誤った順序で着地します。どれも静かで 状況依存の失敗です — あなたのデータでは動き、他人のデータで壊れます。

ExcelMaster なら、代わりに 結果を述べるだけで済みます。「A 列のすべての空白を、その上の値で埋めて」や「可視行だけを Summary シートにコピーして」と言えば、ガード付きの SpecialCells 呼び出し、Is Nothing の 確認、可視のみの経路を書いてくれます — 空白のないファイルでも、半分の行を隠すフィルターでも 生き延びる版です。ブックもコードもあなたの手元に残り、最初のエッジケースでのクラッシュを 飛ばせます。

よくある質問

なぜ SpecialCells は「セルが見つかりません」エラーを出すのですか?

検索領域の中に、指定した種類に合うセルが1 つもないとき、SpecialCellserror 1004 を 発生させるからです — 「該当なし」を空の範囲ではなくエラーとして扱います。空白セルのない領域を SpecialCells(xlCellTypeBlanks) に通すと、マクロは止まります。呼び出しを On Error Resume Next で包み、On Error GoTo 0 で戻し、使う前に If Not result Is Nothing を判定しましょう。

VBA でフィルター後の可視セルだけを選択するには?

xlCellTypeVisible を使います。rng.SpecialCells(xlCellTypeVisible) です。AutoFilter のあと、 フィルターで外れた行は隠れていても範囲の一部なので、素の .Copy はそれらを含めます。 SpecialCells(xlCellTypeVisible) を経由すると、コピー・色づけ・削除を、ユーザーが実際に 見えている行だけに限定できます。

xlCellTypeConstants と xlCellTypeFormulas の違いは何ですか?

xlCellTypeConstants は、直接入力した値 — あなたが打ち込んだ数値や文字列 — を持つセルを 返します。xlCellTypeFormulas は、数式を持つセルを返します。どちらも結果の型で絞る任意の 第 2 引数を取るので、SpecialCells(xlCellTypeFormulas, xlErrors) は、いま #REF!#DIV/0! のようなエラーを表示している数式セルだけを返します。

VBA ですべての空白セルを一度に埋めるには?

SpecialCells(xlCellTypeBlanks)(空白なしエラーへのガード付き)で空白を選び、選択全体へ 1 つの 文で書き込みます。各空白の上の値をコピーするには、gaps.FormulaR1C1 = "=R[-1]C" を使い、 続いて gaps.Value = gaps.Value で数式を静的な値に固定します。ループは要りません。

SpecialCells は連続した範囲を返しますか?

たいていは返しません。頼んだ空白や可視セルはしばしば散らばっているので、SpecialCells複数エリアの参照を返します。.Count はすべてのエリアを合わせたセルの総数で、.Areas.Count はそれらが成す別ブロックの数です。ほとんどの操作はすべてのエリアを一度に扱います。連続する 各ブロックを個別に扱う必要があるときだけ For Each a In result.Areas でループしましょう。

検証環境

検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-08-16。

関連ガイド: VBA Union · VBA Intersect · VBA AutoFilter · VBA CurrentRegion · VBA On Error