第2回 直感！スグに使える業務向けVBA汎用プロシージャ(文字列検索)

第0回で配布しました汎用プロシージャのコードの紹介と簡単な解説をやっていきたいと思います！
以下のリンクから .bas ファイルをダウンロードできます（zipファイル）

https://drive.google.com/file/d/11qEUTsq87UItzoKu2okX5WgEopRercCb/view?usp=drive_link

今回ご紹介するプロシージャは
| プロシージャ名		| 概要						|
|-------------------------------|-----------------------------------------------|
| SpeedUp	| 処理の高速化(画面更新停止など)を一括制御	|
| SearchRow | 指定列から文字列検索(完全一致orあいまい)		|
| SearchCol	| 指定行から文字列検索(完全一致orあいまい)		|

前回は指定行または列の最終の番号を取得するというものでしたが、今回は指定行または列の指定した文字が何番目に存在するのかを取得するプロシージャになっております。さらに指定した文字列と完全一致だけでなく指定した文字列が含まれていれば、すなわち**あいまい検索**の機能も付けました。

では、SearchRow / SearchColのコードをまとめてご紹介します！

## SearchRow
~~~
Function SearchRow(wordForSearch As String, colNumber As Long, searchMethod As Long, searchDirection As Long, Optional targetSheet As Worksheet) As Long
'------------------------------------------------------------------------------------------------------------------------------
'　概要　　｜任意のシートで、指定列にある検索対象文字列と一致する最初の行番号を取得
'------------------------------------------------------------------------------------------------------------------------------
'　引数１　｜wordForSearch - 検索対象対象文字列(Srting型)
'　引数２　｜colNumber - 対象の列番号(Long型)
'　引数３　｜searchMethod - 検索方法(1:完全一致、2:あいまい検索)(Long型)
'　引数４　｜searchDirection - 検索の方向(1:順方向、2:逆方向)(Long型)
'　引数５　｜targetSheet - 対象のワークシートオブジェクト(規定値:ActiveSheet)(Worksheet型)
'------------------------------------------------------------------------------------------------------------------------------
'　戻り値　｜Long型 - 検索対象の行番号(データが無い場合は0)
'------------------------------------------------------------------------------------------------------------------------------
'　実装　　｜Ver.1.0.0(2025/04/20:新規)
'------------------------------------------------------------------------------------------------------------------------------
    
    Dim vLoop   As Long '行ループカウンタ
    
    If targetSheet Is Nothing Then Set targetSheet = ActiveSheet
    
    'ユーザー定義エラー
    If colNumber < 1 Then
        Err.Raise vbObjectError + 1001, "SearchRow", "引数は1以上の整数にしてください"
    End If
    If searchMethod <> 1 And searchMethod <> 2 Then
        Err.Raise vbObjectError + 1002, "SearchRow", "引数は1(完全一致)または2(あいまい検索)にしてください"
    End If
    If searchDirection <> 1 And searchDirection <> 2 Then
        Err.Raise vbObjectError + 1003, "SearchRow", "引数は1(順方向)または2(逆方向)にしてください"
    End If
    
    '文字列の検索および行番号の取得
    With targetSheet
        If searchDirection = 1 Then
            For vLoop = 1 To .Cells(.Rows.Count, colNumber).End(xlUp).Row
                If searchMethod = 1 Then
                    If .Cells(vLoop, colNumber) = wordForSearch Then
                        SearchRow = vLoop
                        Exit Function
                    End If
                ElseIf searchMethod = 2 Then
                    If .Cells(vLoop, colNumber) Like "*" & wordForSearch & "*" Then
                        SearchRow = vLoop
                        Exit Function
                    End If
                End If
            Next vLoop
        ElseIf searchDirection = 2 Then
            For vLoop = .Cells(.Rows.Count, colNumber).End(xlUp).Row To 1 Step -1
                If searchMethod = 1 Then
                    If .Cells(vLoop, colNumber) = wordForSearch Then
                        SearchRow = vLoop
                        Exit Function
                    End If
                ElseIf searchMethod = 2 Then
                    If .Cells(vLoop, colNumber) Like "*" & wordForSearch & "*" Then
                        SearchRow = vLoop
                        Exit Function
                    End If
                End If
            Next vLoop
        End If
    End With
    
End Function
~~~

## SearchCol
~~~
Function SearchCol(wordForSearch As String, rowNumber As Long, searchMethod As Long, searchDirection As Long, Optional targetSheet As Worksheet) As Long
'------------------------------------------------------------------------------------------------------------------------------
'　概要　　｜任意のシートで、指定行にある検索対象文字列と一致する最初の列番号を取得
'------------------------------------------------------------------------------------------------------------------------------
'　引数１　｜wordForSearch - 検索対象対象文字列(Srting型)
'　引数２　｜rowNumber - 対象の行番号(Long型)
'　引数３　｜searchMethod - 検索方法(1:完全一致、2:あいまい検索)(Long型)
'　引数４　｜searchDirection - 検索の方向(1:順方向、2:逆方向)(Long型)
'　引数５　｜targetSheet - 対象のワークシートオブジェクト(規定値:ActiveSheet)(Worksheet型)
'------------------------------------------------------------------------------------------------------------------------------
'　戻り値　｜Long型 - 検索対象の列番号(データが無い場合は0)
'------------------------------------------------------------------------------------------------------------------------------
'　実装　　｜Ver.1.0.0(2025/04/20:新規)
'------------------------------------------------------------------------------------------------------------------------------
    
    Dim hLoop       As Long '列ループカウンタ
    
    If targetSheet Is Nothing Then Set targetSheet = ActiveSheet
    
    'ユーザー定義エラー
    If rowNumber < 1 Then
        Err.Raise vbObjectError + 1001, "SearchCol", "引数は1以上の整数にしてください"
    End If
    If searchMethod <> 1 And searchMethod <> 2 Then
        Err.Raise vbObjectError + 1002, "SearchCol", "引数は1(完全一致)または2(あいまい検索)にしてください"
    End If
    If searchDirection <> 1 And searchDirection <> 2 Then
        Err.Raise vbObjectError + 1003, "SearchCol", "引数は1(順方向)または2(逆方向)にしてください"
    End If
    
    '文字列の検索および列番号の取得
    With targetSheet
        If searchDirection = 1 Then
            For hLoop = 1 To .Cells(rowNumber, .Columns.Count).End(xlToLeft).Column
                If searchMethod = 1 Then
                    If .Cells(rowNumber, hLoop) = wordForSearch Then
                        SearchCol = hLoop
                        Exit Function
                    End If
                ElseIf searchMethod = 2 Then
                    If .Cells(rowNumber, hLoop) Like "*" & wordForSearch & "*" Then
                        SearchCol = hLoop
                        Exit Function
                    End If
                End If
            Next hLoop
        ElseIf searchDirection = 2 Then
            For hLoop = .Cells(rowNumber, .Columns.Count).End(xlToLeft).Column To 1 Step -1
                If searchMethod = 1 Then
                    If .Cells(rowNumber, hLoop) = wordForSearch Then
                        SearchCol = hLoop
                        Exit Function
                    End If
                ElseIf searchMethod = 2 Then
                    If .Cells(rowNumber, hLoop) Like "*" & wordForSearch & "*" Then
                        SearchCol = hLoop
                        Exit Function
                    End If
                End If
            Next hLoop
        End If
    End With
    
End Function
~~~

本プロシージャは…使うことはあんまりないけどいざというときに大活躍する、そんなプロシージャになっています(笑)、主な活躍のフィールドは**データベース処理**かなと考えています。
Excelをよく使う方向けに表現するならば、**VLOOKUP**、**HLOOKUP**の応用版だと捉えていただければと思います。

簡単ではありますが図を用いて使用例と動作の解説をしていきます。

## 動作解説
![Excel-2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046902/080a7f1a-c2bf-4317-9213-33e152030636.png)

このようなシートがあったとしましょう。よくある社員のデータベース、もう少し一般的な言い方をすると**リレーショナルデータベース**ですね。

このデータベースに対してSearchRow / SearchColを使ってみましょう！

~~~
Sub Main()
    
    Dim a As Long
    Dim b As Long
    Dim c As Long
    Dim d As Long
    Dim e As Long
    Dim f As Long
    Dim g As Long
    Dim h As Long
    
    a = SearchRow("10001001", 1, 1, 1)
    b = SearchRow("田中", 2, 1, 2)
    c = SearchRow("1003", 6, 2, 1)
    d = SearchRow("1000", 6, 1, 1)
    e = SearchCol("名前", 1, 1, 1)
    f = SearchCol("東京", 4, 1, 1)
    g = SearchCol("東京", 7, 1, 1)
    h = SearchCol("経理", 9, 2, 1)
    
    Debug.Print "a = " & a
    Debug.Print "b = " & b
    Debug.Print "c = " & c
    Debug.Print "d = " & d
    Debug.Print "e = " & e
    Debug.Print "f = " & f
    Debug.Print "g = " & g
    Debug.Print "h = " & h
    
End Sub
~~~

すべてSheet1(=アクティブなシート)内の検査であるため、第5引数は省略しております。そして実行結果が以下のようになります。

![Excel-2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046902/48cf85f6-7ff5-4eda-be75-52dc6ef89c6a.png)

a~hまでの変数ごと見ていきますと
・a："10001001"は1列目の2行目にあるので戻り値は**2**
・b："田中"さんは2列目の最終行から検索すると最初に7行目でヒットするので戻り値は**7**
　　※最初に一致したときの値のみを返します
・c："1003"を含む文字列は6列目の4行目にあるので戻り値は**4**
・d："1000"を含む文字列が6列目に存在しないため戻り値は**0**
・e："名前"は1行目の2列目にあるので戻り値は**2**
・f："東京"は4行目の5列目にあるので戻り値は**5**
・g："東京"は7行目に存在しないので戻り値は**0**
・h："経理"を含む文字列は9行目の3列目に存在するので戻り値は**3**

![Excel-2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046902/50463866-715c-42e8-9ecc-d20d818ba8d4.png)


といった動作になります。恐らくこの中で一番よく使われるパターンは**e**になりますね。例えば大量のExcelファイル(=リレーショナルデータベース)から何らかの情報を取り出したいときに欲しい情報の列番号を検索するという使い方になります。抽出対処のExcelファイルたちのフォーマットが同じであれば必要ありませんが違う場合もそれなりにあるかと思いますのでそのような場面に遭遇した際は使ってみてください！

また**b**のような最終行または最終列から検索をかける必要があるパターンもたまにありますので抽出したいExcelファイルの中身がどのようになっているのかを一度ざっくりでもよいので把握したうえで必要な処理を選んであげると業務自動化へ大きく前進できます！

## 直感！VBAシリーズ記事一覧
もしよろしければ他の記事もご覧ください！

https://qiita.com/Reko/items/3e482f9a73353e964f00

https://qiita.com/Reko/items/af042ae33cdc01e1dc96

https://qiita.com/Reko/items/c2dab7b0e8207f8049df

https://qiita.com/Reko/items/b5abcdf614cef5d4073a

https://qiita.com/Reko/items/3451339e723a34ac7897

https://qiita.com/Reko/items/40c66556ac51a8006ea6

https://qiita.com/Reko/items/0269b2bece07a675e797

https://qiita.com/Reko/items/e2d0d0bf2dea4feface1

https://qiita.com/Reko/items/b995c3da88d25f6e0104

https://qiita.com/Reko/items/bc97d79599cfd431b2f3

https://qiita.com/Reko/items/1731aaddfc6e50c209df

https://qiita.com/Reko/items/554a47f2aa944e2eec5e

https://qiita.com/Reko/items/e8253ac68ccafba44ad3