ねらい:コードをいじらず「マッピング表」だけで動く汎用高速ツール
毎回「この列をあっちの列に」「この値はこう変換して」と、VBAの中身を書き換えていませんか。
それをやっている限り、ツールは作る人にしか触れないし、修正のたびにあなたが呼ばれます。
ここで目指すのは、こういう世界です。
どのシートの、どの列から、どのシートの、どの列へ写すか。
そのとき、どんな変換(トリム・全角半角・コード変換など)をかけるか。
これを「マッピング設定シート」に書くだけで、
VBAのコードは一切触らずに、高速に処理が走る“汎用エンジン”を作ることです。
「マッピングを変えれば別の業務にもそのまま流用できる」
これが“超再利用部品”としての価値です。
設計の全体像:設定シート+汎用エンジンという二段構え
シート構成のイメージ
最低限、次の3つを用意します。
Config シート
マッピング設定を書くシート。ここが“頭脳”です。
Source シート
元データが入っているシート。CSVを貼るでも、DBから持ってくるでもOK。
Target シート
マッピングに従って整形された結果を出すシート。
VBA側は、「Config を読んで、Source から Target にコピー・変換する」汎用エンジンだけを持ちます。
業務ごとの違いは、Config の中身だけで表現します。
マッピング設定シートの設計
Config シートの列構成
Config シートに、次のような列を用意します。
A列:有効フラグ(Y の行だけ処理する)
B列:SourceSheet(元シート名)
C列:SourceCol(元の列番号または列記号)
D列:TargetSheet(出力シート名)
E列:TargetCol(出力列番号または列記号)
F列:Transform(変換関数名。空ならそのままコピー)
例えば、こんな感じです。
| A | B | C | D | E | F |
|---|---|---|---|---|---|
| Y | Source | A | Target | A | TrimText |
| Y | Source | B | Target | B | Normalize_ZenHan |
| Y | Source | C | Target | C | Map_CodeToName |
| N | Source | D | Target | D |
この1行が「1つのマッピングルール」です。
「Source の B列を Target の B列にコピーするとき、Normalize_ZenHan をかける」といった意味になります。
変換関数群(Transform)のテンプレ
1セルを変換する小さな関数を用意する
変換はすべて「1セルを受け取って、変換後の1セルを返す」関数として作ります。
これをいくつか用意しておき、Config の F列に名前を書くだけで呼び分けます。
例:前後スペース削除
' ModTransform.bas
Option Explicit
Public Function TrimText(ByVal s As Variant) As Variant
If IsError(s) Then
TrimText = s
ElseIf IsNull(s) Or s = "" Then
TrimText = s
Else
TrimText = Trim$(CStr(s))
End If
End Function
VB例:全角英数字 → 半角
Public Function Normalize_ZenHan(ByVal s As Variant) As Variant
If IsError(s) Then
Normalize_ZenHan = s
ElseIf IsNull(s) Or s = "" Then
Normalize_ZenHan = s
Else
Normalize_ZenHan = StrConv(CStr(s), vbNarrow)
End If
End Function
VB例:コード → 名称(簡易マスタマッピング)
ここでは、簡単のために Select Case で書きますが、実務では別シートのマスタを Dictionary 化して呼ぶ形にしてもOKです。
Public Function Map_CodeToName(ByVal s As Variant) As Variant
Dim code As String
If IsError(s) Then
Map_CodeToName = s
Exit Function
End If
code = CStr(s)
Select Case code
Case "01": Map_CodeToName = "東京"
Case "02": Map_CodeToName = "大阪"
Case "03": Map_CodeToName = "名古屋"
Case Else: Map_CodeToName = "#未定義:" & code
End Select
End Function
VBポイントは、「Transform 関数は全部同じインターフェース(引数1つ、戻り値1つ)」に揃えることです。
これで、汎用エンジンからは「名前だけ指定して呼ぶ」ことができます。
汎用エンジン:Config を読んで一気にコピー・変換する
マッピング設定を読み込む構造体
まず、Config の1行をメモリに持つための構造体を定義します。
' ModMappingEngine.bas
Option Explicit
Private Type MapRow
Enabled As Boolean
SourceSheet As String
SourceCol As Long
TargetSheet As String
TargetCol As Long
TransformName As String
End Type
VB列記号(A,B,C…)で書かれている場合も扱えるように、列番号に変換する関数も用意します。
Private Function ColToNumber(ByVal colRef As Variant) As Long
If IsNumeric(colRef) Then
ColToNumber = CLng(colRef)
Else
ColToNumber = Range(CStr(colRef) & "1").Column
End If
End Function
VBConfig シートからマッピング配列を作る
Private Function LoadMappings() As Variant
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Config")
Dim lastRow As Long
lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
If lastRow < 2 Then
LoadMappings = Empty
Exit Function
End If
Dim data As Variant
data = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, 6)).Value
Dim maps() As MapRow
ReDim maps(1 To UBound(data, 1))
Dim i As Long
For i = 1 To UBound(data, 1)
maps(i).Enabled = (UCase$(CStr(data(i, 1))) = "Y")
maps(i).SourceSheet = CStr(data(i, 2))
maps(i).SourceCol = ColToNumber(data(i, 3))
maps(i).TargetSheet = CStr(data(i, 4))
maps(i).TargetCol = ColToNumber(data(i, 5))
maps(i).TransformName = CStr(data(i, 6))
Next
LoadMappings = maps
End Function
VBここで、「Config の2行目以降」を MapRow の配列に変換しています。
Enabled が False の行は、後でスキップします。
高速処理のための“お作法”を挟む
画面更新や再計算を止める共通処理を用意しておきます。
Private Sub SpeedOn()
Application.ScreenUpdating = False
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
End Sub
Private Sub SpeedOff()
Application.Calculation = xlCalculationAutomatic
Application.EnableEvents = True
Application.ScreenUpdating = True
End Sub
VBメインエンジン:マッピングに従って行単位で処理する
ここが心臓部です。
Public Sub RunMappingEngine()
Dim maps As Variant
maps = LoadMappings()
If IsEmpty(maps) Then
MsgBox "Configにマッピングがありません。", vbInformation
Exit Sub
End If
SpeedOn
Dim i As Long
Dim maxRow As Long
maxRow = GetMaxRowAcrossSources(maps)
Dim r As Long
For r = 2 To maxRow
For i = LBound(maps) To UBound(maps)
If maps(i).Enabled Then
ApplyOneMapping maps(i), r
End If
Next i
Next r
SpeedOff
MsgBox "マッピングエンジンの処理が完了しました。", vbInformation
End Sub
VBここでやっていることはシンプルです。
Config からマッピング配列を読み込む。
全マッピングの中で「最大の行数」を求める(GetMaxRowAcrossSources)。
1行ずつ、全マッピングを回して「Source から Target へコピー・変換」する。
GetMaxRowAcrossSources は、各 SourceSheet の最終行を見て、その最大値を返す関数です。
Private Function GetMaxRowAcrossSources(ByVal maps As Variant) As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Dim i As Long
For i = LBound(maps) To UBound(maps)
If maps(i).Enabled Then
If Not dict.Exists(maps(i).SourceSheet) Then
dict.Add maps(i).SourceSheet, 0
End If
End If
Next
Dim ws As Worksheet
Dim sheetName As Variant
Dim maxRow As Long
maxRow = 0
For Each sheetName In dict.Keys
Set ws = ThisWorkbook.Worksheets(CStr(sheetName))
Dim r As Long
r = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
If r > maxRow Then maxRow = r
Next
GetMaxRowAcrossSources = maxRow
End Function
VB1つのマッピングを1行分適用する処理
Private Sub ApplyOneMapping(ByRef m As MapRow, ByVal rowIndex As Long)
Dim wsS As Worksheet, wsT As Worksheet
Set wsS = ThisWorkbook.Worksheets(m.SourceSheet)
Set wsT = ThisWorkbook.Worksheets(m.TargetSheet)
Dim srcVal As Variant
srcVal = wsS.Cells(rowIndex, m.SourceCol).Value
Dim outVal As Variant
If m.TransformName <> "" Then
outVal = Application.Run(m.TransformName, srcVal)
Else
outVal = srcVal
End If
wsT.Cells(rowIndex, m.TargetCol).Value = outVal
End Sub
VBここが「マッピング設定だけで動く」ポイントです。
どのシートのどの列から、どのシートのどの列へ。
どの変換関数を通すか。
それを MapRow が全部持っているので、
エンジン側は「その通りに動くだけ」です。
例題:顧客CSVを貼るだけで「整形済み顧客マスタ」を作る
想定する元データ(Source)
Source シートに、システムから出力された顧客CSVを貼るとします。
A列:顧客コード(前後スペースあり)
B列:顧客名(全角半角混在)
C列:地域コード(01,02,03…)
Target シートには、次のように出したいとします。
A列:顧客コード(Trim済み)
B列:顧客名(全角→半角)
C列:地域名(コード→名称)
Config シートはこう書きます。
| A | B | C | D | E | F |
|---|---|---|---|---|---|
| Y | Source | A | Target | A | TrimText |
| Y | Source | B | Target | B | Normalize_ZenHan |
| Y | Source | C | Target | C | Map_CodeToName |
あとは、Source にCSVを貼って、RunMappingEngine を実行するだけです。
コードは一切触りません。
重要ポイントの深掘り:この型を“本当に現場で使える”ようにする工夫
「行単位」ではなく「配列一括処理」にするとさらに高速
今のエンジンは「行×マッピング」の二重ループで、セルを直接読んで書いています。
数万行を超えると、ここがボトルネックになります。
本気で高速化するなら、
Source シートごとに UsedRange を配列に読み込む。
Target シートごとに配列を用意して、そこに書き込む。
最後に配列を一括でシートに書き戻す。
という構造に変えると、一気に速くなります。
ただし、コードは少し複雑になるので、まずは「行単位版」でロジックを固めてから、
必要に応じて配列版に進化させるのがおすすめです。
Transform を「設定表で切り替えられる」ことの威力
TransformName を Config に書くだけで、変換ロジックを差し替えられる、というのはかなり強力です。
TrimText を TrimTextPlus に変えたい。
Normalize_ZenHan を Normalize_ZenHanKanaOnly に変えたい。
こういう変更が、「VBAを開かずに」Config の F列を書き換えるだけで済みます。
現場の担当者にとっても、「ここを変えれば動きが変わる」と目に見える形になるので、
ツールが“ブラックボックス化”しにくくなります。
マッピング設定の「検証」をどうするか
Config にミスがあると、当然おかしな結果になります。
存在しないシート名を書いてしまう。
列記号を間違える。
TransformName をタイプミスする。
これを防ぐために、
RunMappingEngine の最初に「Config の妥当性チェック」を入れる。
存在しないシート名・列・関数名があれば、処理を止めてメッセージを出す。
という“前提条件チェック”をテンプレに組み込んでおくと、現場での事故が減ります。
まとめ:マッピング設定だけで動く高速ツールは「Config × Transform × Engine」の三位一体
このテンプレの本質は、次の三つです。
Config シートに「どこからどこへ、どう変換するか」を全部書く。
Transform モジュールに「1セルをどう変換するか」の小さな関数を並べる。
Engine モジュールは「Config を読み、Transform を呼びながら Source → Target を埋める」だけに徹する。
この型を一度作ってしまえば、
顧客マスタ整形
商品マスタ整形
CSV取り込み後の前処理
システム間インターフェースの項目マッピング
など、列構成が違うだけの仕事は、Config を変えるだけで次々にこなせます。
