未入力行の抽出
「空白行だけ抜きたい」「必須項目が未入力の行だけ抽出したい」—初心者でもすぐ使える4つの定番アプローチを、落とし穴対策込みでまとめました。単一列の空白から、複数列の必須チェック、見た目の空白(スペースのみ)まで対応します。
最短:AutoFilterで空白抽出(単一列)
Sub Extract_Blanks_AutoFilter_OneColumn()
With Range("A1").CurrentRegion
.AutoFilter Field:=1, Criteria1:="=" 'A列が空白の行だけ表示
.SpecialCells(xlCellTypeVisible).Copy Worksheets("抽出").Range("A1")
.AutoFilter '解除
End With
End Sub
VB- ポイント:
- “=“ は空白条件。見出しを含む表(CurrentRegion)を前提に最短で動く。
- スペースやタブが入っている「見た目空白」は抽出されないため、後述の「スペース除去」を併用。
定番:ループ+Ifで柔軟判定(複数列の必須チェック)
Sub Extract_Blanks_MultiRequired()
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim last As Long: last = rg.Row + rg.Rows.Count - 1
Dim out As Worksheet: Set out = Worksheets("抽出")
Dim outRow As Long: outRow = 2
Dim r As Long
For r = rg.Row + 1 To last 'ヘッダーを除く
Dim nameVal As String, qtyVal As String, priceVal As String
nameVal = Trim$(CStr(Cells(r, "A").Value)) '必須1:商品名
qtyVal = Trim$(CStr(Cells(r, "B").Value)) '必須2:数量
priceVal = Trim$(CStr(Cells(r, "C").Value)) '必須3:単価
'どれか未入力(空文字)なら抽出
If nameVal = "" Or qtyVal = "" Or priceVal = "" Then
Rows(r).Copy Destination:=out.Rows(outRow)
outRow = outRow + 1
End If
Next
End Sub
VB- ポイント:
- Trimで前後の空白・改行を除去してから判定。スペースだけの「見た目空白」も未入力扱いになる。
- 必須列が増えてもOr条件に足すだけで拡張可能。
爆速:配列で一括チェック→まとめて貼り付け
Sub Extract_Blanks_ArrayFast()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Application.EnableEvents = False
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim v As Variant: v = rg.Value '表丸ごと配列へ
Dim rowsHit As Object: Set rowsHit = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 2 To UBound(v, 1) '2行目から(ヘッダー除外)
Dim nameVal As String, qtyVal As String, priceVal As String
nameVal = Trim$(CStr(v(i, 1)))
qtyVal = Trim$(CStr(v(i, 2)))
priceVal = Trim$(CStr(v(i, 3)))
If nameVal = "" Or qtyVal = "" Or priceVal = "" Then
rowsHit(i) = True
End If
Next
If rowsHit.Count > 0 Then
Dim out() As Variant, cnt As Long: cnt = rowsHit.Count
ReDim out(1 To cnt, 1 To UBound(v, 2))
Dim idx As Variant, rOut As Long: rOut = 1
For Each idx In rowsHit.Keys
Dim c As Long
For c = 1 To UBound(v, 2)
out(rOut, c) = v(idx, c)
Next
rOut = rOut + 1
Next
Worksheets("抽出").Range("A1").Resize(1, UBound(v, 2)).Value = rg.Rows(1).Value 'ヘッダー
Worksheets("抽出").Range("A2").Resize(cnt, UBound(v, 2)).Value = out
End If
Cleanup:
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VB- ポイント:
- セル往復を避けて高速。10万行規模でも耐える。
- 必須列の位置は v(i, 列番号) で自在に設定できる。
1列だけの本当に空白セルを拾う(SpecialCells)
Sub Extract_Blanks_SpecialCells()
Dim col As Range: Set col = Range("A2:A100000") '対象列
On Error Resume Next
Dim blanks As Range: Set blanks = col.SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If Not blanks Is Nothing Then
'空白セルの行を丸ごと抽出へコピー
Dim c As Range, out As Worksheet: Set out = Worksheets("抽出")
Dim outRow As Long: outRow = 2
For Each c In blanks
Rows(c.Row).Copy Destination:=out.Rows(outRow)
outRow = outRow + 1
Next
End If
End Sub
VB- ポイント:
- 真の空白セルのみ対象。スペースや関数の空文字(””)は含まれないことがあるため、用途に応じて選ぶ。
スペースのみ・関数の空文字も「未入力」扱いにする
Sub NormalizeSpaces_ThenExtract()
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim last As Long: last = rg.Row + rg.Rows.Count - 1
'対象列の前処理:スペース・改行を削除してから空白判定(A~C列例)
Dim r As Long, cols As Variant: cols = Array("A", "B", "C")
For r = rg.Row + 1 To last
Dim k As Long
For k = LBound(cols) To UBound(cols)
With Cells(r, cols(k))
.Value = Trim$(Replace(Replace(CStr(.Value), vbCrLf, " "), vbTab, " "))
End With
Next
Next
'前処理後は AutoFilter の空白抽出が効きやすい
With Range("A1").CurrentRegion
.AutoFilter Field:=1, Criteria1:="="
.AutoFilter Field:=2, Criteria1:="="
.AutoFilter Field:=3, Criteria1:="="
.SpecialCells(xlCellTypeVisible).Copy Worksheets("抽出").Range("A1")
.AutoFilter
End With
End Sub
VB- ポイント:
- 改行・タブ・スペースを正規化して「実質空白」に。関数で “” を返している場合は値化が必要なこともある。
ラベル未入力の行を抽出(ヘッダー別名にも対応)
Sub Extract_Blanks_ByHeaderNames()
Dim head As Range: Set head = Range("A1").CurrentRegion.Rows(1)
Dim colName As Long, colQty As Long, colPrice As Long
colName = GetColumnByHeader("商品名", head)
colQty = GetColumnByHeader("数量", head)
colPrice= GetColumnByHeader("単価", head)
If colName * colQty * colPrice = 0 Then
MsgBox "必要な見出しが見つかりません": Exit Sub
End If
Dim rg As Range: Set rg = Range("A1").CurrentRegion
Dim v As Variant: v = rg.Value
Dim rowsHit As Object: Set rowsHit = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = 2 To UBound(v, 1)
If Trim$(CStr(v(i, colName))) = "" Or _
Trim$(CStr(v(i, colQty))) = "" Or _
Trim$(CStr(v(i, colPrice)))= "" Then
rowsHit(i) = True
End If
Next
If rowsHit.Count > 0 Then
Dim out() As Variant, cnt As Long: cnt = rowsHit.Count
ReDim out(1 To cnt, 1 To UBound(v, 2))
Dim idx As Variant, rOut As Long: rOut = 1
For Each idx In rowsHit.Keys
Dim c As Long
For c = 1 To UBound(v, 2)
out(rOut, c) = v(idx, c)
Next
rOut = rOut + 1
Next
Worksheets("抽出").Range("A1").Resize(1, UBound(v, 2)).Value = rg.Rows(1).Value
Worksheets("抽出").Range("A2").Resize(cnt, UBound(v, 2)).Value = out
End If
End Sub
Function GetColumnByHeader(ByVal headerName As String, ByVal headerRange As Range) As Long
Dim hit As Range
Set hit = headerRange.Find(What:=headerName, LookAt:=xlWhole, LookIn:=xlValues)
GetColumnByHeader = IIf(hit Is Nothing, 0, hit.Column)
End Function
VB- ポイント:
- 見出しの名称が変わる現場でも壊れにくい。見出し→列番号を動的に取得。
安全・高速ラップ(大量時の基本)
Sub SafeWrapStart()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
End Sub
Sub SafeWrapEnd()
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VB- ポイント:
- 前後停止→復帰で体感が大きく改善。エラー時も復帰できるよう
On Error GoTo Cleanupを併用。
- 前後停止→復帰で体感が大きく改善。エラー時も復帰できるよう
よくある落とし穴と対策
- スペースだけ・改行だけで「空白じゃない」に見える
- 対策: Trim+Replaceで前処理してから判定。タブや改行も消す。
- 関数の空文字(””)は空白扱いにならないことがある
- 対策: 値化(.Value = .Value)や前処理で文字列化→Trim判定へ。
- AutoFilter対象の列選択ミス
- 対策: CurrentRegionを使うか、ヘッダー位置をFindで動的に取得。
- セル往復で遅い
- 対策: 範囲→配列へ読み込み、まとめて判定→一括貼り付け。
- 「必須列」の定義変更でコードが壊れる
- 対策: 見出し→列番号の動的取得(GetColumnByHeader)で耐久性を確保。
例題で練習
'例1:A列が空白の行だけ抽出
Sub Example_OneColumnBlank()
With Range("A1").CurrentRegion
.AutoFilter Field:=1, Criteria1:="="
.SpecialCells(xlCellTypeVisible).Copy Worksheets("抽出").Range("A1")
.AutoFilter
End With
End Sub
'例2:商品名/数量/単価のいずれかが未入力の行を抽出(Trim込み)
Sub Example_MultiRequiredBlank()
Call Extract_Blanks_ArrayFast '本文の高速テンプレをそのまま使用
End Sub
'例3:SpecialCellsで「真の空白セル」行だけ抽出(A列)
Sub Example_SpecialCellsBlank()
Call Extract_Blanks_SpecialCells
End Sub
VB