TL;DR —
Filter(sourceArray, match)は、部分文字列matchを含む要素だけを収めた 新しい 0 始まりの配列 を返します。これはシートではなく メモリ上の配列 に対する検索で あり、AutoFilterとは無関係です。噛みついてくるのは 3 つ。部分文字列 に一致すること (だから"AB"は"CAB"を残す)、既定で大文字小文字を区別する こと(無視するにはvbTextCompareを渡す)、そして一致なしの結果はエラーではなくUBound = -1の空配列 で あることです。任意の第 3 引数Includeはこれを反転させます。Filter(a, "x", False)は"x"を含ま ない 要素をすべて残します。
Sub FilterDemo()
Dim names As Variant, hits As Variant
names = Array("Smith", "Jones", "Smithson", "Adams")
hits = Filter(names, "Smith") ' "Smith" を含む要素を残す
Debug.Print hits(0) ' Smith <- インデックス 0、常に 0 始まり
Debug.Print hits(1) ' Smithson <- 部分文字列一致、単語全体ではない
Debug.Print UBound(hits) ' 1 <- 2 件ヒット: インデックス 0 と 1
hits = Filter(names, "smith") ' 小文字 -> 既定では一致しない
Debug.Print UBound(hits) ' -1 <- エラーではなく空配列
End Sub
人をつまずかせる 2 つの引数を含めた完全な構文です。
Filter(sourceArray, match, [include], [compare])
' 1 次元配列 テキスト True/False vbTextCompare = 大文字小文字を無視
この記事で学べること
- 考え方の軸 — Filter は配列を探し、残すべきものを返す
- なぜ
FilterはAutoFilterでは ない のか、そしてそれぞれをいつ使うのか - 部分文字列の罠:
Filterは値全体ではなく単語の内側に一致する - 大文字小文字の区別と、
vbTextCompareによる解決 - 空結果の罠(
UBound = -1)とガードの仕方 - フィルターを反転する
Include:=False、そして Split と Join との往復
考え方の軸:Filter はシートではなく配列を探す
Filter は InStr の配列版です。InStr が「この
テキストは 1 つの 文字列の中にあるか、どこにあるか?」を問うのに対し、Filter は「これらの文字列の
どれが このテキストを含むか?」を問い、含むものだけを収めた真新しい配列を返します。リストを渡せば、
より短いリストが返ってきます。
この捉え方が、いつ手を伸ばすべきかをそのまま教えてくれます。すでにメモリ上に 1 次元の文字列配列 がある — Split で切り出した断片、Dictionary のキー、 Dir が返すファイル名の一覧 — そして、何かに言及している部分集合が欲しい、という ときです。誰もが書くあのループを 1 行で置き換えます。
' 誰もが最初に書く長いやり方
Dim i As Long, n As Long
ReDim keep(UBound(names)) As String
For i = 0 To UBound(names)
If InStr(1, names(i), "Smith") > 0 Then
keep(n) = names(i): n = n + 1
End If
Next i
ReDim Preserve keep(n - 1)
' 同じことを 1 回の呼び出しで
keep = Filter(names, "Smith")
消し去るべき混同:Filter は AutoFilter ではない
これは「なぜ Filter がシートで動かないのか」という質問の最大の発生源です。答えは、たまたま 1 つの語を 共有しているだけの、無関係な 2 つの道具を握っている、というものです。両者は互いの変種ではありません。
Filter() — 関数 |
AutoFilter — メソッド |
|
|---|---|---|
| 対象 | メモリ上の 1 次元配列 | ワークシートの Range |
| 返すもの | 新しい小さな配列 | 何も返さない — UI で 行を隠す |
| セルに触れる? | 決して触れない | はい、目に見えるシートの状態 |
| 一致の種類 | 部分文字列、大文字小文字を区別 | 条件により 等しい / 含む / より大きい |
| こういうとき使う | すでに配列を持っている | ユーザーにフィルターした行を見せたい |
データがセルにあって絞り込みたいなら、この関数ではなく AutoFilter を、多条件の
コピーなら Advanced Filter を使います。Filter() が居場所を得るのは、
データを配列に取り込んだ あと です。よくある正しいパイプラインはこうです。列を読み、それを 1 次元配列に
平坦化し(Transpose の仕事)、それからシートにいっさい触れずにメモリ上で
Filter する。
罠 1:Filter は値全体ではなく部分文字列に一致する
Filter は、一致テキストが要素の どこかに 現れる要素をすべて残します。これは「含む」検索にとっては
機能であり、「等しい」検索にとっては自分の足を撃つ罠です。
Dim codes As Variant, r As Variant
codes = Array("AB", "ABC", "CAB", "XY")
r = Filter(codes, "AB")
' r は "AB"、"ABC"、そして "CAB" を保持する — "AB" を含むすべての要素
"AB" に等しい要素だけが欲しかったなら、Filter は誤った道具です — 完全一致はできません。完全一致の
所属判定には、Dictionary(dict.Exists(key))か Application.Match を
使います。「含む」が本当に意図していることであるときに Filter を使いましょう。
罠 2:Filter は既定で大文字小文字を区別する
そのままでは Filter は バイナリ 比較を使います — "smith" は "Smith" に一致しません。これは
多くの人の頭の中の既定とは逆で、黙って空配列を返します。第 4 引数がこれを直します。
r = Filter(names, "smith") ' バイナリ -> "Smith" を取りこぼす
r = Filter(names, "smith", True, vbTextCompare) ' テキスト -> "Smith"、"SMITH"、"smith" に一致
第 4 引数に届くには、第 3 引数(Include、ここでは True)を必ず与えなければならない点に注意して
ください。代わりに、モジュール先頭の Option Compare Text は、そのモジュール内のすべての文字列比較を —
Filter も含めて — 大文字小文字を無視にします。手軽ですが、モジュール全体の挙動を変えてしまうので、
効果を局所的にしたいときは呼び出しごとに vbTextCompare を渡しましょう。
罠 3:一致なしは空配列を返し、Include は反転させる
何にも一致しない Filter はエラーを出しません — 長さ 0 の有効な配列を返し、その UBound は
-1 です。For i = 0 To UBound(r) のループはこれを回っても無害に何もしませんが、r(0) に触ろうと
すると「インデックスが有効範囲にありません」で落ちます。インデックスを取る前に UBound でガード
しましょう。
r = Filter(names, "Zzz")
If UBound(r) < 0 Then
MsgBox "No matches."
Else
MsgBox (UBound(r) + 1) & " match(es) found." ' 件数 = UBound + 1
End If
そして、ほとんど誰も覚えていない引数、Include。既定は True(一致を残す)です。False を渡すと
Filter は 反転 します — 一致を含ま ない 要素をすべて残すのです。これが、リストから項目を 1 行で
取り除くやり方です。
' "temp" を含むパスをすべて捨てる
clean = Filter(paths, "temp", False)
意見:Filter は手元にある配列のためのもの — そして Split-Filter-Join の一行
Filter は優れた接着剤であり、貧弱なエンジンです。すでに 1 次元の文字列配列になっていて、「含む」が
本当の問いであるデータで輝きます — フォルダーの一覧を刈り込む、Split から得たトークンを絞る、ログ配列
からエラー行だけを残す。完全一致が欲しくなった瞬間(Dictionary を使う)、データがまだセルにある瞬間
(AutoFilter を使う)、あるいは要素が文字列でない瞬間(Filter は文字列に変換してテキストとして比較
するので、数値では静かに誤らせる)には、誤った答えになります。
最良の使い方は、3 つの関数のパイプラインの真ん中になることです。Split が解析し、Filter が残し、Join が 組み立て直す — 15 行のループを置き換える 1 つの式です。
' 1 つの CSV 行から、"2026" に言及するフィールドだけ残し、つなぎ直す
result = Join(Filter(Split(line, ","), "2026"), ", ")
この 1 行は、クラスター全体の縮図です。Split が文字列を配列にし、Filter が
部分集合を取り、Join がそれを 1 つに畳み込む — ループなし、インデックス計算なし、
off-by-one なし。
ExcelMaster の活用
フィルターすることが目的であることは、めったにありません。目的は「このエクスポートから期限切れの請求書を 抜き出し、テスト行を落として、顧客コードを寄こして」です。列を配列に読み込み、平坦化し、大文字小文字の 区別をガードし、空結果を処理し、残ったものをつなぎ直す頃には、配管が、本当に欲しかった 1 つの答えを 覆い隠してしまいます。ExcelMaster なら、その目的を普通の言葉で — 「期限切れでテスト用でないすべての請求書の顧客コードを一覧にして」 — と 言うだけです。そして、データを読み、本物の一致ロジックを適用し、まずファイルをバックアップする Python を 生成します。あなたは欲しい結果を説明するだけ。大文字小文字の区別も、空のケースも、エッジも、それが 処理します。
よくある質問
VBA の Filter 関数は何をしますか?
Filter(sourceArray, match) は、部分文字列 match を含む sourceArray の要素だけを収めた新しい配列を
返します。元は 1 次元配列でなければならず、結果は常に 0 始まりです。メモリ上の配列を検索してより小さな
配列を返すだけで、セルは一切変更しません。
VBA の Filter は AutoFilter と同じですか?
いいえ。Filter() はメモリ上の 1 次元配列の部分集合を取り、新しい配列を返す関数です。AutoFilter は
条件に基づいて可視シートの行を隠すワークシートのメソッドです。両者は名前を共有するだけで、ほかには何も
ありません — データがセルにあるなら AutoFilter、すでに配列なら Filter() です。
テキストが明らかに一致するのに VBA の Filter が何も返さないのはなぜですか?
ほぼ確実に大文字小文字の区別です。Filter は既定でバイナリ比較を使うので、"smith" は "Smith" に
一致しません。第 4 引数に vbTextCompare を渡すか(Filter(a, "smith", True, vbTextCompare))、
モジュール先頭に Option Compare Text を置きましょう。
VBA の Filter で項目を除外するには?
第 3 引数 Include に False を渡します。Filter(paths, "temp", False) は "temp" を含ま ない
要素をすべて返します。Include を省略するか True にすると Filter は一致を残し、False にすると
非一致を残します。
VBA の Filter が何か一致を見つけたか確認するには?
結果の UBound を調べます。一致なしの Filter は、エラーではなく UBound が -1 の空配列を返すので、
If UBound(result) < 0 Then は「何も一致しなかった」を意味します。配列は 0 始まりなので、一致の件数は
UBound(result) + 1 です。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-03.
関連ガイド: VBA Join · VBA Transpose · VBA Split · VBA AutoFilter · VBA Dictionary
