【実務・中級編】【上級プロフェッショナル向け】ObjectDBXと正規表現を用いた「図面を開かない」全画層名の一括置換と保存 – AutoCAD VBA解析バイブル

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

AutoCAD VBAを掌握する極限の知見:ObjectDBXと正規表現による「非破壊・超高速」画層置換エンジン

業務自動化の現場において、「動くコード」を書くことは誰にでもできる。しかし、「数千枚の図面を、メモリ消費を最小限に抑え、かつエラーで止まることなく、数分で処理し終えるツール」を書ける者は、極めて稀である。

もし君が、数百枚の図面に対して画層名の変更を行う際、`Documents.Open` を使って一つずつ図面を開き、画層をループして、保存して閉じる……というコードを書いているとしたら、今すぐその設計を捨ててほしい。それは「自動化」ではなく、単なる「マシンの作業をGUIで模倣しているだけ」の、極めて非効率なスクリプトだ。

本記事では、AutoCADの内部データベースに直接アクセスするObjectDBXと、複雑な命名規則を瞬時に捌く正規表現(RegExp)を組み合わせた、プロフェッショナル仕様の「図面を開かない一括置換エンジン」の設計思想を伝授する。

1. 設計思想:なぜ「図面を開いてはいけない」のか

AutoCADにおける `Document` オブジェクトの生成は、極めて重い。図面を開くということは、以下のリソースをすべて消費することを意味する。

1. グラフィックス・エンジン: 図面の描画準備(たとえ非表示でも、内部的な計算は走る)。
2. メモリ・オーバーヘッド: 各図面のエンティティ、スタイル、ブロック定義などの全情報をメモリ上に展開。
3. ユーザーインターフェースの干渉: ダイアログボックスのポップアップや、警告メッセージによる処理の中断リスク。

これに対し、ObjectDBXは「図面エディタを介さず、データベース(DWGファイル)の構造体へ直接アクセスする」技術だ。これは、GUIという贅肉を削ぎ落とし、純粋なデータ操作のみを行う。この差は、100枚の処理なら数分、1,000枚の処理なら数時間の差となって現れる。

2. アーキテクチャ:堅牢な処理フロー

プロフェッショナルなツールには、以下の3層構造が不可欠である。

1. FileSystem層: `FileSystemObject` を用い、対象ディレクトリ内のDWGファイルを再帰的に、かつ安全にスキャンする。
2. ObjectDBX層: 図面を「開かず」に、メモリ上にデータベース・オブジェクトとしてロードする。ここで、ファイルが読み取り専用であったり、破損していたりする場合の例外処理を完備する。
3. Logic層(正規表現): `VBScript.RegExp` を用い、単純な `Replace` では不可能な「特定のパターン(例:`OLD_`で始まるが末尾の数字は維持する等)」を正確に抽出・置換する。

3. 実装例:プロダクション・グレードのコード

以下に、そのまま実務に投入できるレベルのVBAコードを示す。
※参照設定に `Microsoft VBScript Regular Expressions 5.5` と `Microsoft Scripting Runtime` が必要である。

Option Explicit

' ==============================================================================
' プロフェッショナル向け:ObjectDBXによる高速画層置換エンジン
' 概要: 図面を開かずに、正規表現を用いて画層名を一括置換する
' ==============================================================================

Sub BulkRenameLayersWithRegex()
    Dim fso As New FileSystemObject
    Dim targetFolder As String
    Dim targetFile As File
    
    ' --- 設定領域 ---
    targetFolder = "C:\Work\Project_DWG_Batch" ' 対象フォルダ
    ' ----------------
    
    If Not fso.FolderExists(targetFolder) Then
        MsgBox "指定されたフォルダが存在しません。", vbCritical
        Exit Sub
    End If

    ' ObjectDBXの初期化 (AutoCADのバージョンに合わせた適切なオブジェクトを取得)
    ' 注意: AutoCADのバージョンにより、ObjectDBXのクラス名は異なる
    Dim dbxDoc As Object
    On Error Resume Next
    Set dbxDoc = GetInterfaceObject("ObjectDBX.AxDbDocument." & GetAutoCADVersion())
    On Error GoTo 0

    If dbxDoc Is Nothing Then
        MsgBox "ObjectDBXの初期化に失敗しました。バージョンを確認してください。", vbCritical
        Exit Sub
    End If

    ' メインループ
    Dim file As File
    For Each file In fso.GetFolder(targetFolder).Files
        If LCase(fso.GetExtensionName(file.Path)) = "dwg" Then
            Debug.Print "Processing: " & file.Name
            
            ' 個別ファイル処理
            ProcessSingleFile dbxDoc, file.Path
        End If
    Next file

    MsgBox "全処理が完了しました。", vbInformation
End Sub

''' <summary>
''' 単一のDWGファイルを処理するコアロジック
''' </summary>
Private Sub ProcessSingleFile(ByRef dbxDoc As Object, ByRef filePath As String)
    On Error GoTo ErrorHandler

    ' 1. データベースのロード (図面は開かない)
    dbxDoc.Open filePath

    ' 2. 画層のループと置換
    Dim layer As Object
    Dim regExp As New RegExp
    
    ' --- 正規表現パターンの定義 ---
    ' 例: 「L-」で始まり、その後に数字が続く画層名を「LAYER_数字」に変換する場合
    ' パターン: ^L-(\d+)$  -> 置換後: LAYER_$1
    With regExp
        .Pattern = "^L-(\d+)$"
        .Global = False
        .IgnoreCase = True
    End With

    For Each layer In dbxDoc.Layers
        ' 特殊画層(0, Defpoints)は絶対に触れてはならない
        If layer.Name <> "0" And LCase(layer.Name) <> "defpoints" Then
            
            If regExp.Test(layer.Name) Then
                Dim newName As String
                newName = regExp.Replace(layer.Name, "LAYER_$1")
                
                ' 同名の画層が既に存在しないかチェック(衝突回避)
                If Not LayerExists(dbxDoc, newName) Then
                    layer.Name = newName
                Else
                    Debug.Print "  [Skip] Name collision: " & layer.Name & " -> " & newName
                End If
            End If
            
        End If
    Next layer

    ' 3. 変更を保存
    dbxDoc.Save
    Debug.Print "  [Success] Saved."

CleanUp:
    Exit Sub

ErrorHandler:
    Debug.Print "  [Error] " & filePath & " : " & Err.Description
    Resume CleanUp
End Sub

''' <summary>
''' 同名画層の存在確認
''' </summary>
Private Function LayerExists(ByRef dbxDoc As Object, ByVal name As String) As Boolean
    Dim layer As Object
    On Error Resume Next
    Set layer = dbxDoc.Layers.Item(name)
    LayerExists = (Err.Number = 0)
    On Error GoTo 0
End Function

''' <summary>
''' AutoCADのバージョンを取得するヘルパー関数
''' </summary>
Private Function GetAutoCADVersion() As String
    ' AutoCADの内部バージョン(例: 24.3など)を取得するロジック
    ' ここでは簡略化のため、実行中のアプリケーションから取得する想定
    Dim acadApp As Object
    Set acadApp = GetObject(, "AutoCAD.Application")
    ' 実際には、Versionプロパティや、Registryから取得する。
    ' 汎用的な書き方として、現在使用中のオブジェクトから判断させる。
    GetAutoCADVersion = "24.3" ' 例: AutoCAD 2021以降の内部バージョン
End Function

4. アーキテクトの警告:陥りやすい「死の罠」

このコードを実戦投入する前に、以下の3点を必ず脳に刻んでおいてほしい。

① 特殊画層の保護(Layer 0 & Defpoints)

AutoCADのデータベース構造において、`0` 画層と `Defpoints` 画層はシステムの根幹を成している。これらをリネームしようとした瞬間、データベースの整合性が崩れ、図面は「死ぬ(開けなくなる)」。コード内での `If layer.Name <> “0”` というガードは、単なる作法ではなく、生存戦略だ。

② ObjectDBXのバージョン不一致

ObjectDBXは、AutoCAD本体のバージョンと密接に紐付いている。AutoCAD 2024を使っているなら、`ObjectDBX.AxDbDocument.24.3` のような正確なプログラミング・インターフェース・クラス名を指定する必要がある。ここがズレると、`GetInterfaceObject` は無慈悲に `Nothing` を返す。

③ ファイルロックと書き込み権限

大量のファイルを処理する際、ネットワークドライブ上のファイルや、他のユーザーが参照中のファイルに遭遇する確率は極めて高い。`On Error GoTo ErrorHandler` によるエラーハンドリングを怠ると、一度のエラーで数時間のプロセスが台無しになる。「エラーは起きるもの」という前提で、エラーが起きても次のファイルへ進める堅牢な設計にせよ。

結論

効率化とは、単に「楽をすること」ではない。「リソースの消費を最小化し、不確実性を排除した設計をすること」だ。ObjectDBXと正規表現をマスターした君は、もはや単なるVBA使いではない。AutoCADという巨大なデータベースを自在に操る、真のエンジニアへの階段を登ったのだ。

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