Excel VBA | 列ごとに自由に計算式を設定できる汎用高速マクロ

Excel VBA VBA
スポンサーリンク

実務で超使える 「列ごとに自由な計算式を設定できる汎用高速マクロ」 を作ります。
ポイントは次の通り:

  • 範囲を自動検出して 配列で読み込み → 配列で処理 → 一括書き戻し(超高速)
  • 列ごとに「モード」と「パラメータ」を設定でき、よく使う処理はプリセットで選べる
  • より複雑なら ユーザー定義マクロ(Custom) を呼び出して拡張可能
  • 実行前に画面更新・再計算をオフにして高速化、終了時に復元

下に「そのまま使えるテンプレコード」と「設定例」「カスタム関数の書き方」「使い方メモ」を付けます。コピペで使って、設定部分を書き換えれば OK です。


フルコード(コピペで動くテンプレ)

Option Explicit

' 汎用高速マクロ(列ごとにモードを指定して処理)
Sub FastColumnProcessor()

    Dim ws As Worksheet
    Set ws = ActiveSheet ' 必要なら Sheets("データ") 等に変える

    Dim lastRow As Long, lastCol As Long
    If Application.WorksheetFunction.CountA(ws.Cells) = 0 Then
        MsgBox "シートにデータがありません。", vbExclamation
        Exit Sub
    End If

    ' --- 自動範囲検出(ヘッダー1行、データ2行目から最終行まで想定) ---
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
    lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
    If lastRow < 2 Then
        MsgBox "データ行がありません。(2行目以降をデータ行と想定)", vbExclamation
        Exit Sub
    End If

    Dim data As Variant
    data = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, lastCol)).Value ' 2次元配列 (1-based)

    Dim r As Long, c As Long

    ' --- 高速化設定 ---
    Dim oldCalc As XlCalculation, oldScreen As Boolean, oldEnableEvents As Boolean
    oldCalc = Application.Calculation
    oldScreen = Application.ScreenUpdating
    oldEnableEvents = Application.EnableEvents
    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual

    On Error GoTo CleanUp

    ' --- 列ごとの設定(ここを編集) ---
    ' 設定の書式: ModeConfig(col) = "モード|パラメータ"
    ' モード例:
    '   "Multiply|2"           : 数値を2倍
    '   "FillIfEmpty|未入力"   : 空白なら指定文字で埋める
    '   "CheckThreshold|100"   : >=閾値なら "OK" それ以外 "NG"
    '   "Concat|1,2"           : 同じ行の列1と列2を結合(列番号はカンマ区切り)
    '   "Formula|=A{r}+B{r}"   : 文字列の式を評価してセルに代入({r} は1行目=データ配列の1に対応)
    '   "Custom|Module1.MyFunc": 自作プロシージャを呼ぶ(戻り値をセルに入れる)
    ' 空白 = その列は処理しない
    Dim ModeConfig() As Variant
    ReDim ModeConfig(1 To lastCol)

    ' --- ここを用途に合わせて書き換える --- (例)
    ' Col 1: 数値を2倍
    ModeConfig(1) = "Multiply|2"
    ' Col 2: 空白なら「未入力」で埋める
    ModeConfig(2) = "FillIfEmpty|未入力"
    ' Col 3: 閾値100で OK/NG
    ModeConfig(3) = "CheckThreshold|100"
    ' Col 4: 列1と列2を結合(例)
    ModeConfig(4) = "Concat|1,2"
    ' Col 5: 任意のExcel式を評価(例:A列 + B列、ただし {r} を行に置換)
    ModeConfig(5) = "Formula|=RC[-4] & ""-"" & RC[-3]" ' R1C1 相対式の例(別方法あり)
    ' Col 6: カスタム関数呼び出しの例(Module1 の MyCustom(colValue, rowArray) を呼ぶ)
    ModeConfig(6) = "Custom|Module1.MyCustom"

    ' --- メイン処理(配列内で完結) ---
    Dim parts() As String, param As String, mode As String
    Dim args() As String
    Dim v As Variant

    For r = 1 To UBound(data, 1) ' data の r は 1 = シート上の行2
        For c = 1 To UBound(data, 2)
            If IsEmpty(ModeConfig(c)) Then GoTo NextCol
            parts = Split(CStr(ModeConfig(c)), "|")
            mode = parts(0)
            If UBound(parts) >= 1 Then
                param = parts(1)
            Else
                param = ""
            End If

            v = data(r, c) ' 元の値

            Select Case LCase(mode)
                Case "multiply"
                    If IsNumeric(v) Then
                        data(r, c) = CDbl(v) * Val(param)
                    End If

                Case "fillifempty"
                    If Trim(CStr(v)) = "" Then data(r, c) = param

                Case "checkthreshold"
                    If IsNumeric(v) Then
                        If CDbl(v) >= Val(param) Then
                            data(r, c) = "OK"
                        Else
                            data(r, c) = "NG"
                        End If
                    Else
                        data(r, c) = "NG"
                    End If

                Case "concat"
                    ' param = "1,2" のように結合する列番号リスト
                    args = Split(param, ",")
                    Dim sb As String
                    sb = ""
                    Dim iCol As Long
                    For iCol = LBound(args) To UBound(args)
                        Dim srcCol As Long
                        srcCol = Val(Trim(args(iCol)))
                        If srcCol >= 1 And srcCol <= UBound(data, 2) Then
                            sb = sb & CStr(data(r, srcCol))
                        End If
                    Next iCol
                    data(r, c) = sb

                Case "formula"
                    ' param は文字列の式。プレースホルダ {r} を実際のシート行番号に置換して Evaluate
                    ' 注意:Evaluate の参照はワークシート依存なので、簡単な式向け
                    Dim expr As String
                    ' シート上の実行行番号を求める(ヘッダー1行のため)
                    Dim sheetRow As Long
                    sheetRow = r + 1
                    expr = Replace(param, "{r}", CStr(sheetRow))
                    ' Evaluate 実行(ワークシートを基準にする)
                    On Error Resume Next
                    Dim evalRes As Variant
                    evalRes = ws.Evaluate(expr)
                    If Err.Number = 0 Then
                        data(r, c) = evalRes
                    End If
                    On Error GoTo 0

                Case "custom"
                    ' param = "Module1.MyFunc" 等。Application.Run で実行、戻り値を入れる
                    ' 引数例: (セル値, 行配列 as Variant)
                    On Error Resume Next
                    Dim ret As Variant
                    ' 行全体(この行の全列データ)を渡す場合:
                    ret = Application.Run(param, data(r, c), Application.Index(data, r, 0))
                    If Err.Number = 0 Then
                        data(r, c) = ret
                    Else
                        ' エラー時は元の値を保持
                        Err.Clear
                    End If
                    On Error GoTo 0

                Case Else
                    ' 未定義モード → 何もしない
            End Select

NextCol:
        Next c
    Next r

    ' --- 書き戻し ---
    ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, lastCol)).Value = data

CleanUp:
    ' --- 後処理(復元)---
    Application.Calculation = oldCalc
    Application.ScreenUpdating = oldScreen
    Application.EnableEvents = oldEnableEvents

    If Err.Number <> 0 Then
        MsgBox "エラー発生: " & Err.Number & " - " & Err.Description, vbExclamation
    End If

End Sub
VB

使い方メモ(設定の仕方)

  • ModeConfig(列番号) = "モード|パラメータ" を編集します(列が多い場合はループで設定してもOK)。
  • Mode の候補(コードで扱っているもの):
    • Multiply|数値 — 数値を掛ける(例:Multiply|2
    • FillIfEmpty|文字列 — 空白なら埋める(例:FillIfEmpty|未入力
    • CheckThreshold|閾値 — 数値 >=閾値 なら “OK”、それ以外は “NG”(例:CheckThreshold|100
    • Concat|1,2,3 — 指定列を順に結合(例:Concat|1,2
    • Formula|式文字列{r} をシート行に置換して Evaluate(注意点下記)
    • Custom|ModuleName.ProcNameApplication.Run でユーザ関数を呼ぶ(詳細下記)

カスタム関数の書き方(例)

Custom モードを使うと、より複雑な処理が可能です。呼ばれる側は Public なプロシージャ/関数で、Application.Run に対応したシグネチャにします。

' Module1 に置く例
Public Function MyCustom(cellValue As Variant, rowArray As Variant) As Variant
    ' 例:列1の値が "X" なら "特記事項" を返す
    If UBound(rowArray) >= 1 Then
        If CStr(rowArray(1)) = "X" Then
            MyCustom = "特記事項"
            Exit Function
        End If
    End If
    ' なければ元の値を返す
    MyCustom = cellValue
End Function
VB
  • 呼び出しは ModeConfig(6) = "Custom|Module1.MyCustom" のように指定します。
  • Application.Run はモジュール名を含めて呼ぶことを推奨します(シートのコードやクラスから呼ぶ場合は少し挙動が違います)。

注意点・実務Tips

  • Formula モードは Evaluate を使うため、式の書き方に注意(参照方式によっては期待どおりに動かない)。可能なら R1C1 形式か、{r} プレースホルダで行番号を置換してから Evaluate する方法を使う。
  • データ内にエラー値(#N/A 等)があると Evaluate や数値判定で問題が発生することがあるので、必要なら事前に IsError でチェックを入れてください。
  • Application.Run は遅くはないが、呼び出し回数が多いとパフォーマンスに影響する。重いロジックは可能な限り配列内で完結させるのがベスト。
  • 大量データ(数十万行)を扱う場合はメモリに注意。64-bit Excel なら大きな配列でも扱いやすいです。
  • 実行前に必ずバックアップ(元シートのコピー)を取っておくこと。

設定例(まとめ)

  • A列(1): Multiply|2 → 値を2倍
  • B列(2): FillIfEmpty|未入力 → 空白なら「未入力」
  • C列(3): CheckThreshold|100 → >=100 → OK / else NG
  • D列(4): Concat|1,2 → 同行の A+B を結合して D に入れる
  • E列(5): Formula|=A{r}+B{r} → A列+B列の計算を評価({r} を行番号に置換)
  • F列(6): Custom|Module1.MyCustom → カスタム関数を呼ぶ

VBA
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました