列名で検索
「見出し行から“この列どこ?”を素早く特定したい」—業務で頻出のニーズを、初心者でも安心して使える定番テンプレでまとめました。Find、MATCH、Dictionary化、自作関数まで、使い分けと落とし穴対策もセットです。
使い分けの指針
- 最短かつ柔軟: Range.Find(完全一致・部分一致・大小文字指定ができる)
- 位置番号で取りたい: WorksheetFunction.Match(完全一致で安定)
- 複数列名を何度も参照: Dictionaryに見出し→列番号をキャッシュ
- どこでも呼べる再利用: 列名→列番号の自作関数(安全版)
基本:Findで列名を探して列番号を取得
Sub FindHeaderColumn_Basic()
Dim headerRow As Range, hit As Range, colNo As Long
Set headerRow = Range("A1:Z1") '見出し行の範囲
Set hit = headerRow.Find(What:="単価", LookAt:=xlWhole, LookIn:=xlValues, MatchCase:=False)
If Not hit Is Nothing Then
colNo = hit.Column 'シート上の列番号(A=1, B=2, ...)
Cells(2, colNo).Value = "ここに結果" '列番号が分かれば参照は簡単
Else
MsgBox "列名が見つかりません: 単価", vbExclamation
End If
End Sub
VB- ポイント:
- 完全一致は xlWhole、部分一致は xlPart。
- 値検索(xlValues)を基本に。数式文字列を探すなら xlFormulas。
- hit.Column はワークシートの実列番号。Range内の相対位置ではない。
安定派:MATCHで列名の位置を取り、列番号へ換算
Sub MatchHeader_ToColumn()
Dim pos As Variant, headerRow As Range, startCol As Long, colNo As Long
Set headerRow = Range("A1:Z1") '見出し行
startCol = headerRow.Column '範囲の開始列番号(A=1など)
On Error Resume Next
pos = Application.WorksheetFunction.Match("単価", headerRow, 0) '0=完全一致
On Error GoTo 0
If Not IsError(pos) Then
colNo = startCol + CLng(pos) - 1 '範囲内位置→シート列番号へ換算
Cells(2, colNo).Value = "ここに結果"
Else
MsgBox "列名が見つかりません: 単価", vbExclamation
End If
End Sub
VB- ポイント:
- MATCHは「範囲内の位置」を返すので、開始列を足して列番号へ換算。
- 近似一致(1/-1)は並べ替えが必要。見出しには使わず「0(完全一致)」を使う。
実務定番:見出し→列番号をDictionaryにキャッシュ
Sub BuildHeaderMap_AndUse()
Dim header As Range: Set header = Range("A1").CurrentRegion.Rows(1) '先頭行を見出しと想定
Dim i As Long, map As Object: Set map = CreateObject("Scripting.Dictionary")
'見出し行を辞書化(キー=列名、値=列番号)
For i = 1 To header.Columns.Count
map(CStr(header.Cells(1, i).Value)) = header.Cells(1, i).Column
Next
'使うときはキーで参照
If map.Exists("単価") Then
Cells(2, map("単価")).Value = "ここに結果"
Else
MsgBox "列名が見つかりません: 単価", vbExclamation
End If
End Sub
VB- ポイント:
- 何度も列名参照する処理を「爆速」に。1回作った辞書を使い回す。
- 型の揺れ対策: キー登録時は CStr で文字列化が安全。
再利用できる安全関数:列名→列番号を返す
Function GetColumnByHeader(ByVal headerName As String, ByVal headerRange As Range, _
Optional ByVal partial As Boolean = False, _
Optional ByVal matchCase As Boolean = False) As Long
Dim hit As Range, lookAt As XlLookAt
lookAt = IIf(partial, xlPart, xlWhole)
Set hit = headerRange.Find(What:=headerName, LookAt:=lookAt, LookIn:=xlValues, MatchCase:=matchCase)
If Not hit Is Nothing Then
GetColumnByHeader = hit.Column
Else
GetColumnByHeader = 0 '0を未検出のシグナルに
End If
End Function
'使い方例
Sub Use_GetColumnByHeader()
Dim colNo As Long
colNo = GetColumnByHeader("単価", Range("A1:Z1"))
If colNo > 0 Then
Cells(2, colNo).Value = "ここに結果"
Else
MsgBox "列名が見つかりません: 単価", vbExclamation
End If
End Sub
VB- ポイント:
- 部分一致や大小文字区別の指定が1行で済む。
- 未検出時は 0 を返すようにし、呼び出し側で分岐。
応用テンプレート
列名の配列で一括取得(存在しない列も丁寧に報告)
Sub GetMultipleColumnsByHeaders()
Dim headers As Variant: headers = Array("商品名", "数量", "単価", "金額")
Dim i As Long, miss As String
For i = LBound(headers) To UBound(headers)
Dim c As Long: c = GetColumnByHeader(headers(i), Range("A1:AZ1"))
If c > 0 Then
Cells(2, c).Value = "OK"
Else
miss = miss & headers(i) & vbCrLf
End If
Next
If Len(miss) > 0 Then
MsgBox "見つからない列名:" & vbCrLf & miss, vbExclamation
End If
End Sub
VB列名で参照して計算(列位置が変わっても壊れない)
Sub Calc_ByHeaderNames()
Dim h As Range: Set h = Range("A1").CurrentRegion.Rows(1)
Dim colQty As Long: colQty = GetColumnByHeader("数量", h)
Dim colPrice As Long: colPrice = GetColumnByHeader("単価", h)
Dim colAmt As Long: colAmt = GetColumnByHeader("金額", h)
If colQty * colPrice * colAmt = 0 Then
MsgBox "必要な列が見つかりません", vbExclamation
Exit Sub
End If
Dim last As Long: last = Cells(Rows.Count, colQty).End(xlUp).Row
Dim r As Long
For r = 2 To last
Cells(r, colAmt).Value = Val(Cells(r, colQty).Value) * Val(Cells(r, colPrice).Value)
End If
End Sub
VBよくある落とし穴と対策
- 見出しに余分な空白/改行が含まれていて一致しない
- 対策: 比較前に
TrimやReplace(…, vbCrLf, "")で正規化。Dictionary化する時点で整えると楽。
- 対策: 比較前に
- 日本語の全角・半角や大文字小文字の揺れ
- 対策: 事前に
StrConv(…, vbNarrow/vbWide)、UCase/LCaseで統一。FindならMatchCase指定、部分一致なら揺れに強い。
- 対策: 事前に
- 部分一致が過剰にヒット(「金額」が「税込金額」にも当たる)
- 対策: 基本は完全一致。やむを得ず部分一致なら、前後記号(例:「[」「]」「()」)や固定語尾を含めて絞る。
- CurrentRegionの見出し行がずれている
- 対策: 見出し行は明示範囲で指定(例:
Range("A1:AZ1"))。テーブル(ListObject)を使ってListColumns("単価").Indexも有効。
- 対策: 見出し行は明示範囲で指定(例:
- 大量の列名参照で遅い
- 対策: 一度Dictionaryに列名→列番号をキャッシュして使い回す。Find/MATCHを都度呼ばない。
例題で練習
'例1:部分一致で「金額」を探し、該当列の値を値貼り付け
Sub Example_FindHeader_Partial_Values()
Dim hit As Range, colNo As Long
Set hit = Range("A1:AZ1").Find(What:="金額", LookAt:=xlPart, LookIn:=xlValues)
If Not hit Is Nothing Then
colNo = hit.Column
With Range(Cells(2, colNo), Cells(10000, colNo))
.Value = .Value
End With
End If
End Sub
'例2:列名から列番号を取り、A列から最終行まで「金額=数量×単価」を計算
Sub Example_CalcByNames()
Dim h As Range: Set h = Range("A1:AZ1")
Dim cQty As Long: cQty = GetColumnByHeader("数量", h)
Dim cPrice As Long: cPrice = GetColumnByHeader("単価", h)
Dim cAmt As Long: cAmt = GetColumnByHeader("金額", h)
If cQty * cPrice * cAmt = 0 Then Exit Sub
Dim last As Long: last = Cells(Rows.Count, cQty).End(xlUp).Row
Range(Cells(2, cAmt), Cells(last, cAmt)).FormulaR1C1 = "=RC[" & (cQty - cAmt) & "]*RC[" & (cPrice - cAmt) & "]"
Range(Cells(2, cAmt), Cells(last, cAmt)).Value = Range(Cells(2, cAmt), Cells(last, cAmt)).Value
End Sub
'例3:列名一覧をDictionary化して、必要列の有無をチェック
Sub Example_HeaderMap_Check()
Dim h As Range: Set h = Range("A1").CurrentRegion.Rows(1)
Dim map As Object: Set map = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 1 To h.Columns.Count
map(Trim(CStr(h.Cells(1, i).Value))) = h.Cells(1, i).Column
Next
Dim need As Variant: need = Array("商品名", "数量", "単価", "金額")
Dim miss As String
For i = LBound(need) To UBound(need)
If Not map.Exists(need(i)) Then miss = miss & need(i) & vbCrLf
Next
If Len(miss) > 0 Then MsgBox("不足列:" & vbCrLf & miss, vbExclamation)
End Sub
VB