前方一致の高速検索
「先頭が〇〇で始まる」を爆速で見つけたいときの定番は、Findの部分一致、Likeのワイルドカード、Dictionary+配列の前処理です。件数や用途ごとに最短テンプレを用意しました。
選び方の指針
- 小〜中規模を素早く1回検索: Range.Find(LookAt:=xlPart、FindNextで全件)
- 大量データを何度も検索: 配列+Dictionary(前方一致用インデックス)
- パターンが明確(「ABC*」など): Like(ワイルドカード)
- 表の絞り込みだけで良い: AutoFilter(Criteria1:=”ABC*”)
基本:Range.Find(前方一致)で全件列挙
Sub PrefixFind_All_FindNext()
Dim src As Range, hit As Range, first As String, prefix As String
Set src = Range("A2:A80000")
prefix = "ABC"
'部分一致指定(前方一致は値を絞るのがコツ)
Set hit = src.Find(What:=prefix, LookIn:=xlValues, LookAt:=xlPart, MatchCase:=False)
If hit Is Nothing Then Exit Sub
first = hit.Address
Do
If Left$(CStr(hit.Value), Len(prefix)) = prefix Then
Debug.Print "ヒット: "; hit.Address; " 値="; hit.Value
End If
Set hit = src.FindNext(hit)
Loop While Not hit Is Nothing And hit.Address <> first
End Sub
VB- ポイント:
- FindのxlPartは「含む」。誤ヒット抑制のため、Leftで前方一致を追加チェック。
- 無限ループ防止は「最初のアドレスに戻ったら終了」。
最短:Like(ワイルドカード)で前方一致
Sub PrefixFind_All_Like()
Dim last As Long, r As Long, prefix As String
prefix = "ABC"
last = Cells(Rows.Count, "A").End(xlUp).Row
For r = 2 To last
If CStr(Cells(r, "A").Value) Like prefix & "*" Then
Cells(r, "A").Interior.Color = RGB(255, 235, 156)
End If
Next
End Sub
VB- ポイント:
- Likeは「prefix*」で前方一致。大小文字はExcelの既定に依存(厳密制御はUCase比較で)。
爆速:配列+Dictionaryで前方一致(大量・繰り返しに強い)
1. 先頭文字でインデックス化(粗く分割して高速化)
Sub PrefixIndex_CharBucket()
Dim rng As Range: Set rng = Range("A2:A200000")
Dim v As Variant: v = rng.Value '配列へ一括
Dim buckets As Object: Set buckets = CreateObject("Scripting.Dictionary") 'key=先頭1文字, value=行番号配列
Dim i As Long, s As String, k As String
For i = 1 To UBound(v, 1)
s = CStr(v(i, 1))
If Len(s) > 0 Then
k = Left$(s, 1)
If Not buckets.Exists(k) Then buckets.Add k, Array()
Call AppendIndexArray(buckets, k, i) '下のヘルパーで配列に追加
End If
Next
'検索(例:prefix="ABC")
Dim prefix As String: prefix = "ABC"
k = Left$(prefix, 1)
If buckets.Exists(k) Then
Dim idxs As Variant: idxs = buckets(k)
For i = LBound(idxs) To UBound(idxs)
s = CStr(v(idxs(i), 1))
If Left$(s, Len(prefix)) = prefix Then
'ヒット処理(例:色付け)
rng.Cells(idxs(i), 1).Interior.Color = RGB(255, 235, 156)
End If
Next
End If
End Sub
Private Sub AppendIndexArray(ByRef dict As Object, ByVal key As String, ByVal index As Long)
Dim arr As Variant: arr = dict(key)
Dim n As Long: On Error Resume Next: n = UBound(arr) + 1: On Error GoTo 0
ReDim Preserve arr(n)
arr(n) = index
dict(key) = arr
End Sub
VB- ポイント:
- 先頭1文字(必要なら2〜3文字)ごとのバケット化で候補を激減。
- 同じprefixで何度も検索する場面(入力補助など)で劇的に速い。
2. 完全な前方インデックス(prefix長Lで作る)
Sub PrefixIndex_Full()
Dim L As Long: L = 3 'インデックスに使う先頭文字数
Dim rng As Range: Set rng = Range("A2:A200000")
Dim v As Variant: v = rng.Value
Dim index As Object: Set index = CreateObject("Scripting.Dictionary") 'key=先頭L文字, value=行番号配列
Dim i As Long, s As String, key As String
For i = 1 To UBound(v, 1)
s = CStr(v(i, 1))
If Len(s) >= L Then
key = Left$(s, L)
If Not index.Exists(key) Then index.Add key, Array()
AppendIndexArray index, key, i
End If
Next
'検索(prefixの長さに応じてキーを決める)
Dim prefix As String: prefix = "ABC"
key = Left$(prefix, L)
If index.Exists(key) Then
Dim idxs As Variant: idxs = index(key)
For i = LBound(idxs) To UBound(idxs)
s = CStr(v(idxs(i), 1))
If Left$(s, Len(prefix)) = prefix Then
rng.Cells(idxs(i), 1).Font.Bold = True
End If
Next
End If
End Sub
VB- ポイント:
- L文字キーで候補を極小に。prefix長に応じてキーを合わせる。
- 先頭ゼロ・大小文字揺れは事前に正規化(例:UCase、文字列化)。
絞り込みだけなら:AutoFilterで前方一致
Sub PrefixFilter()
With Range("A1").CurrentRegion
.AutoFilter Field:=1, Criteria1:="ABC*"
'可視行を抽出など
.SpecialCells(xlCellTypeVisible).Copy Worksheets("抽出").Range("A1")
.AutoFilter
End With
End Sub
VB- ポイント:
- 「表示上の抽出」なら最少コードで実用的。
入力補助(オートコンプリート風)
Sub Prefix_Autocomplete()
Dim prefix As String: prefix = InputBox("先頭文字を入力(例:ABC)")
If Len(prefix) = 0 Then Exit Sub
Dim rng As Range: Set rng = Range("A2:A50000")
Dim v As Variant: v = rng.Value
Dim list As Object: Set list = CreateObject("System.Collections.ArrayList")
Dim i As Long, s As String
For i = 1 To UBound(v, 1)
s = CStr(v(i, 1))
If Left$(UCase$(s), Len(prefix)) = UCase$(prefix) Then
list.Add s
If list.Count >= 50 Then Exit For '候補上限
End If
Next
If list.Count = 0 Then
MsgBox "候補なし": Exit Sub
End If
list.Sort
Worksheets("候補").Range("A2").Resize(list.Count, 1).Value = WorksheetFunction.Transpose(list.ToArray)
End Sub
VB- ポイント:
- 大小文字無視の前方一致で候補を上限付き表示。
- 高速用途は前述のインデックス化に置き換え可。
安全・高速ラップ(大量時の基本)
Sub SpeedWrap_Start()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
End Sub
Sub SpeedWrap_End()
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VB- ポイント:
- 前後で停止→復帰するだけで体感が大きく改善。
- エラー時でも復帰するようにOn ErrorでCleanupへ。
よくある落とし穴と対策
- 前方一致なのに「含む」まで拾ってしまう
- 対策: FindはxlPartで拾い、Leftで前方一致確認を必ず追加。
- 先頭ゼロや大小文字の違いで漏れる
- 対策: 比較前にCStr/UCase、必要ならStrConvで半角・全角統一。
- 行ごとのセルアクセスで遅い
- 対策: まず範囲を配列へ読み込んでから判定。インデックス化で候補を絞る。
- 複数回の検索で毎回全走査してしまう
- 対策: バケット/L文字インデックスを作って再利用。
- 無限ループ(FindNext)
- 対策: 最初のアドレスを記録して、戻ったら終了。
例題で練習
'例1:Find+Leftで前方一致の全件を赤文字
Sub Example_FindPrefixAll()
Dim rng As Range, hit As Range, first As String, prefix As String
Set rng = Range("A2:A50000")
prefix = "PRD"
Set hit = rng.Find(What:=prefix, LookAt:=xlPart, LookIn:=xlValues)
If hit Is Nothing Then Exit Sub
first = hit.Address
Do
If Left$(CStr(hit.Value), Len(prefix)) = prefix Then hit.Font.Color = vbRed
Set hit = rng.FindNext(hit)
Loop While Not hit Is Nothing And hit.Address <> first
End Sub
'例2:Likeで「ORD*」に一致する行を抽出へコピー
Sub Example_LikePrefixExtract()
Dim last As Long, r As Long, s As String, outRow As Long
last = Cells(Rows.Count, "A").End(xlUp).Row: outRow = 2
For r = 2 To last
s = CStr(Cells(r, "A").Value)
If s Like "ORD*" Then
Rows(r).Copy Destination:=Worksheets("抽出").Rows(outRow)
outRow = outRow + 1
End If
Next
End Sub
'例3:インデックス(先頭3文字)で前方一致を高速色付け
Sub Example_Index3PrefixColor()
Call PrefixIndex_Full '上で定義したサブルーチンをそのまま利用
End Sub
VB