フォルダ内のファイル名から指定の文字列を検索する関数

以下がタイトルのVBAです。

Private Sub 使用例()
    Dim filePath() As String  ' ファイルパスを格納する動的配列
    Dim folderPath(1) As String  ' 検索するフォルダのパスを格納
    folderPath(0) = "H:\temp"
    folderPath(1) = "C:\TEMP"

    Dim 検索文字(1) As String  ' 検索する文字列の配列
    検索文字(0) = "2"
    検索文字(1) = "4"

    Dim 除外文字(1) As String  ' 除外する文字列の配列
    除外文字(0) = "t"
    除外文字(1) = "w"

    Dim 先頭限定 As Boolean: 先頭限定 = False  ' 検索文字がファイル名の先頭に限定するかどうか

    ' フォルダ内のファイルから条件に合致するファイルを検索
    Call GetFilePathFromFolders(folderPath(), 検索文字(), 除外文字(), filePath(), 先頭限定)

    ' 結果をデバッグ出力
    If IsInitialized(filePath) Then
        Call debugPrintArray(filePath)
    Else
        Debug.Print "配列が空です"
    End If
End Sub

'**************************************
'* 複数のフォルダから、文字列を検索して、ファイル名を返す。
'* folderPath:フォルダのパスを格納した配列
'* 検索文字():検索する文字列を格納した配列
'* 除外文字():除外する文字列を格納した配列。この文字列が含まれるファイルは除外
'* filePath:ファイル名のフルパスを返すため、参照渡しとしている
'* 先頭限定:Trueのとき、検索文字は、先頭にあるときのみ該当。省略時はFalse
Sub GetFilePathFromFolders(ByRef folderPath() As String, ByRef 検索文字() As String, _
                ByRef 除外文字() As String, ByRef filePath() As String, _
                Optional ByVal 先頭限定 As Boolean = False)
    Dim i As Long
    For i = LBound(folderPath) To UBound(folderPath)
        If folderPath(i) <> "" Then
            Call GetFilePath(folderPath(i), 検索文字(), 除外文字(), filePath(), 先頭限定)
        End If
    Next i
End Sub

'**************************************
'* 文字列を検索して、ファイル名を返す。
'* folderPath:フォルダのパス
'* 検索文字():検索する文字列を格納した配列
'* 除外文字():除外する文字列を格納した配列
'* filePath:ファイル名のフルパスを返すため、参照渡しとしている
'* 先頭限定:Trueのとき、検索文字は、先頭にあるときのみ該当。省略時はFalse
Sub GetFilePath(ByVal folderPath As String, ByRef 検索文字() As String, _
                ByRef 除外文字() As String, ByRef filePath() As String, _
                Optional ByVal 先頭限定 As Boolean = False)
    Dim fso As Object
    Dim folder As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set folder = fso.GetFolder(folderPath)
    
    ' フォルダ内のファイル検索を開始
    Call FileSerch(folder, 検索文字(), 除外文字(), filePath(), 先頭限定)
    
    ' クリーンアップ
    Set folder = Nothing
    Set fso = Nothing
End Sub

'*******************************
'* フォルダ内のすべてのファイルから、特定の文字列を含むファイルのフルパスを取得する
'* folder:フォルダオブジェクト
'* 検索文字():検索する文字列を格納した配列
'* 除外文字():除外する文字列を格納した配列
'* filePath:ファイル名のフルパスを返すため、参照渡しとしている
'* 先頭限定:Trueのとき、検索文字は、先頭にあるときのみ該当。省略時はFalse
Private Sub FileSerch(ByRef folder As Object, ByRef 検索文字() As String, _
                ByRef 除外文字() As String, ByRef filePath() As String, _
                Optional ByVal 先頭限定 As Boolean = False)
    Dim file As Object
    Dim subFolder As Object
    Dim 該当 As Boolean
    Dim i As Long

    ' フォルダ内のすべてのファイルを処理
    For Each file In folder.Files
        該当 = True
        
        ' 検索条件に合致するかどうかを確認
        For i = LBound(検索文字) To UBound(検索文字)
            If 先頭限定 Then
                If InStr(1, file.Name, 検索文字(i), vbTextCompare) <> 1 Then
                    該当 = False
                End If
            Else
                If InStr(1, file.Name, 検索文字(i), vbTextCompare) = 0 Then
                    該当 = False
                End If
            End If
        Next i
        
        ' 除外条件に合致しないかを確認
        For i = LBound(除外文字) To UBound(除外文字)
            If InStr(1, file.Name, 除外文字(i), vbTextCompare) > 0 And 除外文字(i) <> "" Then
                該当 = False
            End If
        Next i
        
        ' 条件に合致するファイルをfilePathに追加
        If 該当 Then
            If IsInitialized(filePath) Then
                ReDim Preserve filePath(UBound(filePath) + 1)
            Else
                ReDim filePath(0)
            End If
            filePath(UBound(filePath)) = file.path
        End If
    Next file

    ' サブフォルダも再帰的に処理
    For Each subFolder In folder.SubFolders
        Call FileSerch(subFolder, 検索文字(), 除外文字(), filePath, 先頭限定)
    Next subFolder
End Sub

'***************************************************
'* 配列が初期化されているかをチェックする
'* https://qiita.com/nkojima/items/7f8299b3299226a97abb
'* ary:対象となる配列。
'* 戻り値:配列が初期化済みならTrue、そうでなければFalseを返す。
Function IsInitialized(ary As Variant) As Boolean
    On Error GoTo NOT_INITIALIZED_ERROR
    ' 動的配列が初期化されていなければ、ここでエラーが発生する。
    Dim length As Long: length = UBound(ary)
    IsInitialized = True
    Exit Function

' 配列が初期化されていない場合はここに飛ばされる。
NOT_INITIALIZED_ERROR:
    IsInitialized = False
End Function

'***************************************************
'* 一次元配列の中身を見やすくイミディエイトウィンドウへ出力する
'* https://vba-create.jp/vba-array-debup-print/
'* tmp:表示させる一次配列
Sub debugPrintArray(ByVal tmp As Variant)
    Dim i As Long
    ' 配列の各要素をイミディエイトウィンドウに出力
    For i = LBound(tmp) To UBound(tmp)
        Debug.Print i & vbTab & tmp(i)  ' 配列要素数と配列の中身を出力
    Next i
End Sub

このVBAコードは、特定のフォルダ内のファイル名から指定された文字列を検索し、条件に合致するファイルパスを配列として返す一連のサブルーチンと関数で構成されています。以下は、コード全体の流れと個々のサブルーチンおよび関数の詳細な解説です。

1. 使用例 サブルーチン

このサブルーチンは、メインのエントリーポイントとして機能します。フォルダパスや検索条件を指定し、検索結果をデバッグ出力します。

1. Dimでの変数の宣言

  • filePath():検索結果としてファイルのフルパスを格納するための動的配列です。後でサイズが変更されることを考慮して宣言されています。
  • folderPath(1):検索対象のフォルダのパスを格納する固定サイズの配列です。この例では、2つのフォルダが設定されています。folderPath(0)に「H:\temp」、folderPath(1)に「C:\TEMP」が設定されています。
  • 検索文字(1):検索に使用する文字列を格納する配列です。ファイル名に「2」または「4」が含まれているファイルを検索する設定です。
  • 除外文字(1):検索から除外する文字列を格納する配列です。ファイル名に「t」または「w」が含まれているファイルは除外されます。
  • 先頭限定ブール値で、検索文字がファイル名の先頭にある場合のみファイルを該当させるかどうかを指定します。この例ではFalseに設定されており、先頭に限定せずファイル名のどこにでも検索文字がある場合に該当します。

2. Call GetFilePathFromFolders

この部分で実際にフォルダ内のファイルを検索します。GetFilePathFromFoldersサブルーチンに対して、フォルダパスの配列、検索文字の配列、除外文字の配列、ファイルパスの参照、先頭限定のフラグを渡しています。

Call GetFilePathFromFolders(folderPath(), 検索文字(), 除外文字(), filePath(), 先頭限定)

3. If IsInitialized(filePath) Then

この部分で、filePath配列が初期化されているかどうかを確認します。IsInitializedという関数は、配列が初期化されているかを判定する役割を持ちます。

  • 初期化されている場合、debugPrintArrayサブルーチンを呼び出して配列の内容をイミディエイトウィンドウに出力します。
  • 初期化されていない場合は、「配列が空です」というメッセージを出力します。
If IsInitialized(filePath) Then
    Call debugPrintArray(filePath)
Else
    Debug.Print "配列が空です"
End If

4. 動作の概要

  1. folderPathに設定されたフォルダ(H:\tempC:\TEMP)内のファイルを検索します。
  2. ファイル名に「2」または「4」が含まれていて、なおかつ「t」または「w」が含まれていないファイルを見つけます。
  3. 条件に合致したファイルのフルパスをfilePath配列に追加します。
  4. 配列が空でなければ、その結果をイミディエイトウィンドウに出力します。

補足情報

  • 配列の参照渡し: filePath()は参照渡しされているため、GetFilePathFromFoldersサブルーチン内で配列が更新され、呼び出し元でもその変更が反映されます。
  • 動的配列の扱い: ReDimキーワードを使用することで、動的配列のサイズを変更し、検索結果に応じてファイルパスを配列に格納します。

2. GetFilePathFromFolders サブルーチン

このサブルーチンは、複数のフォルダを処理し、各フォルダ内でファイル検索を行います。

このVBAコードでは、複数のフォルダ内から指定された条件に合うファイルを検索し、そのファイルのフルパスを配列に格納するサブルーチン GetFilePathFromFolders の仕組みについて説明します。

GetFilePathFromFolders の全体の流れ

  1. 引数の説明:
    • folderPath():検索対象の複数のフォルダパスを格納する配列です。複数フォルダの中で、特定の文字列を含むファイルを検索するために使用します。
    • 検索文字():検索したい特定の文字列を格納する配列です。ファイル名にこれらの文字列が含まれているファイルを探します。
    • 除外文字():除外したい文字列を格納する配列です。ファイル名にこの文字列が含まれる場合、そのファイルは検索結果から除外されます。
    • filePath():検索結果としてフルパスを格納する配列です。参照渡しされており、処理の結果、この配列に検索で見つかったファイルのパスが追加されます。
    • 先頭限定:オプション引数で、True に設定すると検索文字がファイル名の先頭にある場合のみ一致と判断します。デフォルトは False です。
  2. 繰り返し処理:
    • For i = LBound(folderPath) To UBound(folderPath):配列 folderPath の中の各フォルダに対して繰り返し処理を行います。配列の最初の要素(LBound)から最後の要素(UBound)までループします。
  3. フォルダが空でないことの確認:
    • If folderPath(i) <> "" Then:フォルダパスが空でないことを確認します。空のフォルダパスは無視して次の処理に進みます。
  4. サブルーチンの呼び出し:
    • Call GetFilePath(folderPath(i), 検索文字(), 除外文字(), filePath(), 先頭限定):現在のフォルダパス(folderPath(i))を基に、GetFilePath という別のサブルーチンを呼び出し、条件に合うファイルを検索します。これによって、フォルダ内のファイルの検索が実行されます。

検索の流れ

GetFilePathFromFolders は、渡された複数のフォルダに対して一つ一つ、GetFilePath サブルーチンを呼び出してファイル検索を行います。ファイルが見つかると、そのフルパスが filePath() 配列に追加され、呼び出し元に返されます。

この関数の利点

  • 複数のフォルダを一度に検索できるため、複数フォルダの中に特定の文字列を含むファイルがあるかを一括して確認できる。
  • 参照渡しでファイルパスの配列を返すため、呼び出し元のサブルーチンでも検索結果を活用することができます。
  • 動的なファイル検索が可能で、検索文字や除外文字を簡単に変更して使用できる。

このサブルーチンは他のフォルダ検索処理と組み合わせることで非常に柔軟なファイル検索を実現します。


3. GetFilePath サブルーチン

指定されたフォルダパス内でファイルを検索し、条件に合致するファイルを見つけます。

  • 役割: 指定されたフォルダのファイルを検索するために FileSerch サブルーチンを呼び出します。
  • CreateObject: FileSystemObject (FSO) を使ってファイルシステムを操作します。

このVBAコードの詳細説明を行います。このサブルーチン GetFilePath は、指定されたフォルダ内のファイル名を検索し、条件に合ったファイルのパスを取得して配列に格納する役割を持っています。引数としては、検索対象のフォルダ、検索する文字列、除外する文字列、およびオプションの検索条件(ファイル名の先頭に限定するかどうか)を受け取ります。

概要

  • folderPath: ファイルを検索する対象フォルダのパスを指定します。これは文字列型の変数です。
  • 検索文字(): 検索したい文字列を格納する配列です。ファイル名にこの文字列が含まれているファイルを検索します。
  • 除外文字(): 除外する文字列を格納した配列です。ファイル名にこの文字列が含まれている場合、そのファイルは検索結果から除外されます。
  • filePath(): 検索で見つかったファイルのフルパスを格納する配列です。参照渡し(ByRef)で指定されているため、処理の結果、この配列に検索結果が保存されます。
  • 先頭限定: このオプション引数が True に設定されている場合、検索文字列がファイル名の先頭にある場合にのみ、そのファイルを検索結果として返します。デフォルトは False です。

詳細な説明

  1. Set fso = CreateObject("Scripting.FileSystemObject")
    • この行で FileSystemObject を作成します。FileSystemObject はファイルやフォルダを操作するためのオブジェクトです。このオブジェクトを使って、指定されたフォルダ内のファイルやサブフォルダを検索します。
  2. Set folder = fso.GetFolder(folderPath)
    • folderPath で指定されたフォルダのオブジェクトを取得します。このフォルダオブジェクトを使用して、フォルダ内のファイルやサブフォルダにアクセスできます。
  3. Call FileSerch(folder, 検索文字(), 除外文字(), filePath(), 先頭限定)
    • FileSerch という別のサブルーチンを呼び出して、実際にフォルダ内のファイルを検索します。folder は対象フォルダオブジェクトで、検索文字除外文字、そして filePath を渡して、条件に合うファイルを探します。このサブルーチン内で、フォルダ内のファイルをチェックし、条件に合ったファイルのフルパスが filePath 配列に追加されます。
  4. クリーンアップ
    • 処理が完了した後、Set folder = NothingSet fso = Nothing でオブジェクトを解放し、メモリをクリーンアップしています。これはVBAでの標準的な手続きで、オブジェクトを使用し終わったらメモリを解放してリソースを節約するために行います。

実行の流れ

  • フォルダの取得: fso.GetFolder で指定フォルダの情報を取得します。
  • ファイルの検索: FileSerch サブルーチンを呼び出して、フォルダ内のファイルを検索します。
  • 条件に合うファイルのフルパスを取得: 検索文字や除外文字を元に条件に合致するファイルのフルパスを、参照渡しされた filePath() 配列に追加します。

このサブルーチンでは、別のサブルーチンである FileSerch を呼び出して、フォルダ内のファイルを実際に検索します。そのため、このサブルーチンは主にフォルダの情報を取得して、検索処理の準備をする役割を担っています。

この関数は、複数のフォルダに対して同じ検索条件でファイルを探したい場合に非常に役立ちます。また、動的配列や参照渡しを使うことで、ファイルのパスを効率よく処理できる仕組みが整っています。


4. FileSerch サブルーチン

指定されたフォルダ内のすべてのファイルを調べ、検索条件に合致するファイルパスを取得します。

  • 役割: フォルダ内のファイルを条件に基づいて検索し、結果をfilePathに追加します。サブフォルダも再帰的に処理します。
  • 検索条件: 検索文字がファイル名に含まれているか、かつ除外文字が含まれていないかを確認します。

このVBAコードのサブルーチン FileSerch は、指定されたフォルダとそのサブフォルダ内の全てのファイルを検索し、特定の条件に合致するファイルのフルパスを取得します。具体的には、検索文字列を含むファイルを探し、条件に合わないファイル(除外文字を含むものなど)は無視します。また、この処理はフォルダ内のファイルだけでなく、そのサブフォルダにも再帰的に適用されます。

概要

  • folder: 検索対象のフォルダオブジェクトです。このフォルダ内のファイルとサブフォルダを処理します。
  • 検索文字(): 検索したい文字列が入った配列です。ファイル名にこの文字列が含まれているファイルを対象とします。
  • 除外文字(): 検索から除外したい文字列が入った配列です。ファイル名にこの文字列が含まれている場合は、検索結果から除外されます。
  • filePath(): 見つかったファイルのフルパスを格納する配列です。参照渡しされており、処理が終わった時点で結果が格納されます。
  • 先頭限定: このオプションが True の場合、検索文字列がファイル名の先頭にあるかどうかを条件にします。False の場合はファイル名のどこかに含まれていれば条件に合致します。

詳細な処理の流れ

  1. フォルダ内のファイルを処理
    • For Each file In folder.Files で、指定されたフォルダ内の全てのファイルを順番に処理します。
    • 各ファイルについて、以下のステップで条件に合致するか確認します。
  2. 検索文字列のチェック
    • 内部のループ For i = LBound(検索文字) To UBound(検索文字) で、指定された複数の検索文字列に対してファイル名にその文字列が含まれているかを調べます。
    • 先頭限定True の場合、InStr 関数を使用してファイル名の先頭から一致するかどうか確認します(InStr(1, file.Name, 検索文字(i), vbTextCompare) <> 1)。False の場合は、ファイル名のどこにあっても合致します(InStr(1, file.Name, 検索文字(i), vbTextCompare) = 0 だと一致しないと判断)。
    • もし1つでも条件に合わない場合、該当 変数を False に設定します。
  3. 除外文字列のチェック
    • 同様に For i = LBound(除外文字) To UBound(除外文字) で、ファイル名に除外文字が含まれていないか確認します。
    • もし除外文字が含まれている場合、該当False に設定し、そのファイルは無視されます。
  4. ファイルパスの保存
    • 条件に合致するファイル(該当True のファイル)の場合、filePath 配列にそのファイルのフルパスを追加します。
    • IsInitialized(filePath)filePath 配列が初期化されているか確認し、初期化されていない場合は ReDim で配列を初期化します。既に初期化されている場合は ReDim Preserve で配列を拡張し、現在の内容を保持しながら新しい要素を追加します。
  5. サブフォルダの再帰的処理
    • For Each subFolder In folder.SubFolders で、現在のフォルダ内の全てのサブフォルダを対象に再帰的に FileSerch を呼び出します。これにより、サブフォルダ内のファイルも同じ条件で検索されます。

ポイント

  • 再帰処理: このサブルーチンはサブフォルダに対して再帰的に呼び出されるため、指定されたフォルダ以下の全ての階層に対して同じ条件でファイル検索が行われます。
  • 動的配列の使用: filePath 配列は動的に拡張されるため、検索結果が何件であっても対応可能です。
  • 参照渡しによる結果の取得: filePath は参照渡しされているため、呼び出し元のサブルーチンで検索結果を直接利用することができます。

このコードは、指定した条件(検索文字列、除外文字列、先頭限定条件)に合ったファイルを効率よく検索し、結果を収集するために設計されています。


5. IsInitialized 関数

このVBA関数 IsInitialized は、配列が初期化されているかどうかを確認するための関数です。動的配列を扱う際に、配列が初期化されていない場合、エラーが発生する可能性があるため、それをチェックするために使用されます。

関数の概要

  • 引数 ary: チェック対象の配列。Variant 型として渡されます。
  • 戻り値: 配列が初期化されている場合は True、初期化されていない場合は False を返します。

処理の流れ

  1. エラーハンドリングの設定:
    • On Error GoTo NOT_INITIALIZED_ERROR によって、配列が初期化されていない場合にエラーが発生すると、エラーハンドリング用のラベル NOT_INITIALIZED_ERROR にジャンプします。これにより、エラーが発生した場合でもコードが停止せず、処理を続けられます。
  2. 配列の上限を確認:
    • UBound(ary) によって配列の上限を取得します。この操作は、配列が初期化されていない場合にはエラーを引き起こします。初期化されていれば上限値が正常に取得でき、次の行に進みます。
  3. 初期化済みであることを示す:
    • IsInitialized = True によって、配列が初期化されていると判断した場合に True を返します。
  4. エラー時の処理:
    • 配列が初期化されていない場合(動的配列が初期化されていない状態)では、エラーが発生し、エラーハンドリング部分 NOT_INITIALIZED_ERROR にジャンプします。
    • IsInitialized = False によって、配列が初期化されていないことを示す False を返します。
  5. 終了:
    • 初期化されていない場合はエラーが発生し、False が返されます。初期化されている場合は、エラーが発生せず True が返されます。

利用方法のポイント

  • 動的配列のチェック: VBAでは動的配列が初期化されていない場合、アクセスしようとするとエラーが発生します。この関数はそのエラーをキャッチして、配列が初期化されているかどうかを安全に確認します。
  • エラーハンドリング: エラーハンドリングを使用しているため、通常のコードの中で配列の状態を確認する際に、処理を止めることなくチェックできます。

このIsInitialized 関数は、以下から引用しています。ありがとうございます。

【ExcelVBA】配列/動的配列の要素数を安全に求める


6. debugPrintArray サブルーチン

このVBAコードは、一次元配列の中身を表示するための関数です。配列の各要素をイミディエイトウィンドウ(VBAエディタ内の「デバッグ用」ウィンドウ)に出力することができます。この関数は、デバッグ目的で、配列の中身を簡単に確認するのに便利です。

関数の説明

パラメータ
  • tmp: 中身を表示する一次元配列。Variant 型として渡されるため、配列の型には依存しません(文字列でも数値でも扱えます)。
処理の流れ
  1. 配列のループ処理:
    • For i = LBound(tmp) To UBound(tmp) というループで、配列 tmp の最初のインデックス(LBound(tmp)) から最後のインデックス(UBound(tmp)) まで繰り返し処理を行います。
  2. イミディエイトウィンドウへの出力:
    • Debug.Print を使用して、配列のインデックス番号と対応する配列の値を表示します。
    • i & vbTab & tmp(i) は、インデックス番号と配列の中身をタブ区切り(vbTab)で表示しています。例として、インデックス番号が 0 で値が "abc" の場合、0 abc というように表示されます。

イミディエイトウィンドウとは

VBA のイミディエイトウィンドウは、コードのデバッグや実行結果を即時に確認できる窓です。Debug.Print を使って、コードの途中結果や変数の値などをここに出力することができ、エラーの原因を特定したり、コードの動作を確認するのに役立ちます。

このdebugPrintArray サブルーチンは、以下から引用しています。ありがとうございます。

一次元配列の中身をイミディエイトウィンドウに全て出力する処理をパーツ化【ExcelVBA】


まとめ

このVBAコードは、フォルダ内のファイルを検索する際に、複数の条件(検索文字と除外文字)を設定してファイルを絞り込む機能を提供しています。検索対象は再帰的にサブフォルダまで処理され、条件に合致したファイルのフルパスが配列に保存されます。

Follow me!