Excel VBA | フィールド定義表から自動でチェックを組み立てる仕組み(メタデータ駆動)

Excel VBA VBA
スポンサーリンク

フィールド定義表を「外部CSV」から読み込むバージョン

これまでの「定義表シート」方式を発展させて、外部CSVファイルに定義をまとめておき、マクロがそれを読み込んでチェックを実行する仕組みです。
CSVにしておけば、Excelを開かずに定義を更新できるので、運用が柔軟になります。

想定するCSVファイル(例:FieldDef.csv)

列番号,項目名,必須,型,最小値,最大値,最大文字数,正規表現
1,氏名,○,文字列,,,50,
2,年齢,○,整数,0,120,,
3,入社日,○,日付,1990/1/1,TODAY,,
4,メール,,文字列,,,100,^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$

マクロコード例

Sub ValidateByCSVDefinition()
    Dim wsData As Worksheet, wsReport As Worksheet
    Dim lastRow As Long, r As Long, output As Long
    Dim fso As Object, ts As Object
    Dim line As String, parts As Variant
    Dim defs As Collection
    Dim def As Variant
    
    ' データ本体シート
    Set wsData = ThisWorkbook.Sheets("Sheet1")
    
    ' 出力先シート準備
    On Error Resume Next
    Set wsReport = ThisWorkbook.Sheets("検証結果")
    On Error GoTo 0
    If wsReport Is Nothing Then
        Set wsReport = ThisWorkbook.Sheets.Add
        wsReport.Name = "検証結果"
    Else
        wsReport.Cells.Clear
    End If
    wsReport.Range("A1:E1").Value = Array("行番号", "列番号", "項目名", "値", "エラー内容")
    output = 2
    
    ' --- CSV定義ファイルを読み込む ---
    Set defs = New Collection
    Set fso = CreateObject("Scripting.FileSystemObject")
    ' CSVファイルのパスを指定(例:ブックと同じフォルダにある場合)
    Dim defPath As String
    defPath = ThisWorkbook.Path & "\FieldDef.csv"
    
    Set ts = fso.OpenTextFile(defPath, 1, False, -1) ' -1 = Unicode/UTF-8
    ts.SkipLine ' 1行目はヘッダ
    
    Do Until ts.AtEndOfStream
        line = ts.ReadLine
        parts = Split(line, ",")
        defs.Add parts
    Loop
    ts.Close
    
    ' --- データを検証 ---
    lastRow = wsData.Cells(wsData.Rows.Count, "A").End(xlUp).Row
    
    For r = 2 To lastRow
        For Each def In defs
            Dim colIdx As Long, fieldName As String, required As Boolean
            Dim fieldType As String, minVal As String, maxVal As String
            Dim maxLen As Long, regex As String
            Dim value As Variant, errs As Variant, msg As String
            
            colIdx = CLng(def(0))
            fieldName = def(1)
            required = (def(2) = "○")
            fieldType = def(3)
            minVal = def(4)
            maxVal = def(5)
            If def(6) <> "" Then maxLen = CLng(def(6)) Else maxLen = 0
            regex = def(7)
            
            value = wsData.Cells(r, colIdx).Value
            
            errs = CollectErrors( _
                IIf(required, CheckRequired(value, fieldName), ""), _
                IIf(maxLen > 0, CheckMaxLength(value, fieldName, maxLen), ""), _
                IIf(fieldType = "整数", CheckInteger(value, fieldName), _
                   IIf(fieldType = "数値", CheckNumber(value, fieldName), _
                   IIf(fieldType = "日付", CheckDate(value, fieldName), ""))), _
                IIf(fieldType = "整数" Or fieldType = "数値", CheckNumberRange(value, fieldName, minVal, maxVal), ""), _
                IIf(fieldType = "日付", CheckDateRange(value, fieldName, minVal, IIf(maxVal = "TODAY", Date, maxVal)), ""), _
                IIf(regex <> "", CheckRegex(value, fieldName, regex, ""), "") _
            )
            
            msg = JoinErrors(errs)
            If msg <> "" Then
                wsReport.Cells(output, "A").Value = r
                wsReport.Cells(output, "B").Value = colIdx
                wsReport.Cells(output, "C").Value = fieldName
                wsReport.Cells(output, "D").Value = value
                wsReport.Cells(output, "E").Value = msg
                wsReport.Cells(output, "E").WrapText = True
                output = output + 1
            End If
        Next def
    Next r
    
    MsgBox "CSV定義に基づく検証が完了しました。エラー件数: " & (output - 2), vbInformation
End Sub
VB

ポイント

  • CSVを外部ファイルとして管理 → Excelを開かずにルール更新可能。
  • FileSystemObject を使ってCSVを1行ずつ読み込み、Splitで配列化。
  • TODAY を特別扱いして「今日まで」などの条件に対応。
  • CollectErrors / CheckRequired / CheckNumber / CheckDate などは前回の「汎用チェック関数ライブラリ」を利用。

応用アイデア

  • CSVをUTF-8で保存して多言語対応。
  • 複数のCSV(顧客用・社員用など)を切り替えて利用。
  • CSVをネットワーク共有フォルダに置いて、全員が同じ定義を参照。

👉 この仕組みを使えば、「定義表をExcelから切り離して外部管理」できるので、システム的な運用に強くなります。

タイトルとURLをコピーしました