【実務・中級編】【上級プロフェッショナル向け】ObjectDBXと正規表現を組み合わせた、図面を開かない「全注釈テキスト」の一括検索・置換保存 – AutoCAD VBA解析バイブル

スポンサーリンク
スポンサーリンク

AutoCAD VBAの極致:ObjectDBXと正規表現による「非破壊・高速」一括データ操作の設計思想

エンジニア諸君、まず最初に問いたい。
君たちが書いているその「数千ファイルのループ処理」は、本当に業務を効率化しているだろうか? それとも、単にコンピュータのリソースを無駄に消費し、ユーザーの待ち時間を増大させているだけだろうか?

もし、君が `Documents.Open` メソッドをループ内で回し、図面を一つずつ画面に展開しながらテキスト置換を行っているとしたら、今すぐその設計を捨ててほしい。それは「自動化」ではなく、単なる「マクロによる手作業の模倣」に過ぎない。

真のプロフェッショナルが目指すべきは、「図面を(GUIとして)開かずに、データベースとして直接操作する」ことだ。

本稿では、AutoCADのバックグラウンド・データベース・エンジンである ObjectDBX と、高度なパターンマッチングを実現する 正規表現 (Regular Expressions) を組み合わせた、極限の高速検索・置換エンジンの設計と実装について解説する。

1. なぜ `Documents.Open` は「プロの選択」ではないのか

大量のDWGファイルを処理する際、通常の `Documents.Open` を使用すると、以下の致命的な問題に直面する。

1. メモリ消費の爆発: 図面を開くたびに、AutoCADはグラフィックス、レイアウト、ダイナミックブロック、スタイル情報など、すべてのリソースをメモリ上に展開する。数千ファイル規模では、OSのメモリ管理が限界を迎え、スワップが発生して速度が著しく低下する。
2. UIの占有: 図面が画面に描画されるプロセス(Regen)が発生するため、処理中にPCを他の作業に使うことが困難になる。
3. エラーによる全停止: 一つの図面が破損しているだけで、GUIベースの処理はエラーダイアログを表示し、プロセス全体が停止してしまう。

これに対し、ObjectDBX は図面を「単なるデータ構造」としてメモリにロードする。GUIの描画プロセスを完全にバイパスするため、通常の `Open` 処理と比較して、10倍から100倍近いスループットを実現できる。

2. 設計の要諦:堅牢なバッチ処理アーキテクチャ

単にコードを書くだけでは足りない。プロダクション環境で動かすためには、以下の3点を設計思想に組み込む必要がある。

① 動的なオブジェクト生成(Late Bindingの徹底)

ObjectDBXのクラス名は、AutoCADのバージョン(2023, 2024…)によって異なる。これを参照設定(Early Binding)で書いてしまうと、バージョンアップのたびにコードが壊れる。`CreateObject` を用いた動的生成が必須だ。

② 正規表現による「意味のある」置換

「特定の文字列」を置換するだけなら `Replace` 関数で十分だ。しかし、実務では「製品番号 `PN-12345` の形式を持つものをすべて置換したい」といった、パターンに基づいた要求が必ず来る。ここで `VBScript.RegExp` を投入する。

③ 徹底したエラー・アイソレーション(隔離)

バッチ処理において、致命的な失敗は「個別のファイルエラー」であって「プログラム全体の停止」であってはならない。`On Error Resume Next` を乱用するのではなく、ファイル単位で `Try-Catch` 的な制御を行い、エラーが発生したファイルはログに記録して次へ進む設計にせよ。

3. 実装例:High-Speed Text Replacer

以下に、実務でそのまま利用可能なレベルの、モジュール化されたプロダクションコードを示す。

' ==============================================================================
' Module: Professional_DBX_Replacer
' Description: ObjectDBXを用いた高速テキスト置換エンジン
' Requirements: Microsoft VBScript Regular Expressions 5.5
' ==============================================================================

Option Explicit

' 処理結果を格納する構造体的な役割のクラスや型を定義すると保守性が高まるが、
' ここでは簡潔にするため、定数とエラーハンドリングに集中する。

Private Const LOG_FILE_PATH As String = "C:\Temp\BatchProcess_Log.txt"

''' <summary>
''' メインエントリポイント:指定フォルダ内の全DWGを走査し、置換を実行する
''' </summary>
Public Sub ExecuteBatchReplacement(ByVal targetFolder As String, ByVal pattern As String, ByVal replacement As String)
    Dim fso As Object
    Dim folder As Object
    Dim file As Object
    Dim dbxDoc As Object
    Dim dbxVersion As String
    
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    ' ログの初期化
    WriteLog "--- Batch Process Started: " & Now & " ---"
    
    ' AutoCADバージョンに応じたObjectDBXのクラス名を取得(例: ObjectDBX.AxDbDocument.24)
    ' 実際には、実行中のAutoCADのバージョンから動的に判定するのがベスト
    dbxVersion = GetDBXClassName()
    
    If Not fso.FolderExists(targetFolder) Then
        MsgBox "Target folder not found.", vbCritical
        Exit Sub
    End If
    
    Set folder = fso.GetFolder(targetFolder)
    
    ' ファイルループ
    For Each file In folder.Files
        If LCase(fso.GetExtensionName(file.Path)) = "dwg" Then
            
            On Error Resume Next
            ' ObjectDBX インスタンスの生成
            Set dbxDoc = CreateObject(dbxVersion)
            
            If Err.Number <> 0 Then
                WriteLog "ERROR: Failed to create ObjectDBX object: " & Err.Description
                Exit Sub
            End If
            
            ' 図面のオープン(バックグラウンド)
            dbxDoc.Open file.Path
            
            If Err.Number <> 0 Then
                WriteLog "SKIP: Could not open file: " & file.Path & " (" & Err.Description & ")"
                Err.Clear
            Else
                ' 置換処理の実行
                If ProcessTextReplacement(dbxDoc, pattern, replacement) Then
                    ' 変更があった場合のみ保存
                    dbxDoc.SaveAs file.Path
                    WriteLog "SUCCESS: Processed and Saved: " & file.Name
                Else
                    WriteLog "INFO: No matches found in: " & file.Name
                End If
                Err.Clear
            End If
            
            ' オブジェクトの解放(メモリリーク防止の要)
            Set dbxDoc = Nothing
            On Error GoTo 0
            
        End If
    Next file
    
    WriteLog "--- Batch Process Finished: " & Now & " ---"
    MsgBox "Process Complete. Check log at: " & LOG_FILE_PATH, vbInformation
End Sub

''' <summary>
''' 図面内の全テキストオブジェクトを走査し、正規表現で置換を行う
''' </summary>
Private Function ProcessTextReplacement(ByRef dbxDoc As Object, ByVal pattern As String, ByVal replacement As String) As Boolean
    Dim regEx As Object
    Dim entity As Object
    Dim isChanged As Boolean
    Dim currentText As String
    
    Set regEx = CreateObject("VBScript.RegExp")
    With regEx
        .Pattern = pattern
        .Global = True
        .IgnoreCase = True
    End With
    
    isChanged = False
    
    ' ModelSpaceおよびPaperSpaceの走査
    ' ObjectDBXでは、Layoutsコレクションを介して各レイアウトのBlockへアクセスする必要がある
    ' ここでは簡略化のためModelSpaceのみを例示するが、実戦では全Layoutを回すべき
    
    ' ModelSpaceの走査
    For Each entity In dbxDoc.ModelSpace
        ' Text または MText かを判定
        If entity.ObjectName = "AcDbText" Or entity.ObjectName = "AcDbMText" Then
            currentText = entity.TextString
            
            ' 正規表現でマッチング
            If regEx.Test(currentText) Then
                entity.TextString = regEx.Replace(currentText, replacement)
                isChanged = True
            End If
        End If
    Next entity
    
    ProcessTextReplacement = isChanged
End Function

''' <summary>
''' AutoCADのバージョンから適切なObjectDBXクラス名を判定する
''' </summary>
Private Function GetDBXClassName() As String
    ' AutoCAD 2024 = 24, 2023 = 24, 2021 = 24... 
    ' ※実際には内部バージョン番号を確認するロジックを組む
    ' ここでは例として 24 を返す
    GetDBXClassName = "ObjectDBX.AxDbDocument.24"
End Function

''' <summary>
''' ログ出力用ユーティリティ
''' </summary>
Private Sub WriteLog(ByVal message As String)
    Dim fso As Object
    Dim ts As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    ' 追記モードで開く
    Set ts = fso.OpenTextFile(LOG_FILE_PATH, 8, True)
    ts.WriteLine message
    ts.Close
End Sub

4. アーキテクトの視点:運用における注意点

このコードを実戦投入する前に、以下の「落とし穴」を理解しておくことだ。

1. ObjectDBXの限界

ObjectDBXは強力だが、万能ではない。例えば、「図面を開いた瞬間に実行されるLISPやスクリプト」は動作しない。また、一部の複雑なダイナミックブロック内の属性(Attribute)の操作には、通常の `Documents.Open` よりも高度なオブジェクト階層の理解が必要になる。

2. メモリリークへの警戒

`Set dbxDoc = Nothing` を忘れることは、プロフェッショナルとして許されない。ループ内でオブジェクトを解放し忘れると、メモリ使用量は指数関数的に増加し、最終的にはAutoCAD自体がクラッシュする。

3. 正規表現のパターン設計

`pattern` に渡す文字列は、極めて慎重に設計せよ。例えば、`.` (ドット) は正規表現では「任意の文字」を意味する。製品番号の `ABC.123` を探したいなら、パターンは `ABC\.123` とエスケープする必要がある。この「エスケープの概念」を理解していないと、意図しないデータ破壊を招く。

結論

自動化ツールの価値は、「動くこと」ではなく、「いかに安全に、いかに速く、いかに大量のデータを処理できるか」で決まる。

`Documents.Open` を卒業し、ObjectDBXと正規表現を使いこなす。このステップを踏むことで、君の書くコードは「ただのスクリプト」から、企業の基幹業務を支える「堅牢なシステム」へと進化するだろう。

健闘を祈る。

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