【実務・中級編】【上級者向け】段落の「書式設定」をプロパティ単位で比較し、差異をレポートする差分解析 – Word VBA解析バイブル

スポンサーリンク

【VBA極致】段落書式の「完全解析」:目に見えない差異を暴く差分検知エンジンの設計

Wordの書式設定は、一見同じに見えても、背後では「スタイル」と「直接書式(Direct Formatting)」が複雑に絡み合っている。多くのエンジニアが `Range.IsEqual` で挫折するのは、それが「内容」までしか見ないからだ。

品質管理(QA)の現場において、「なぜかレイアウトが崩れる」「スタイルが意図せず上書きされる」という現象を追うとき、我々は「プロパティ単位の徹底解剖」を行う必要がある。今回は、Word VBAの深淵に潜り、二つの段落を分子レベルで比較するデバッグ・エンジンの設計思想を伝授する。

1. なぜ「簡易比較」が罠なのか

Wordの `Paragraph` オブジェクトには膨大なプロパティが存在する。`Font`、`ParagraphFormat`、`Style`…。これらを単に比較演算子で比べるのは愚策だ。

  • 落とし穴1:Null値(未定義)の扱い

Wordのプロパティは「混在」している場合 `wdUndefined` を返す。これを無視して `True/False` だけで比較すると、予期せぬ論理エラーを引き起こす。

  • 落とし穴2:再計算コスト

ループ内で `Paragraph.Range.Font` に何度もアクセスすると、WordのDOMを何度も再走査するため、ドキュメントが長大になるほど処理速度が指数関数的に低下する。

真のエンジニアは、「差異があるプロパティだけを抽出するリストアップ方式」を採用する。

2. プロダクション級・差分解析エンジン

このコードは、二つの `Paragraph` オブジェクトを渡し、不一致な項目を即座に特定する。辞書(Scripting.Dictionary)を用いることで、後続のレポート出力やDB格納にも対応可能な設計としている。

Option Explicit

‘ @brief 二つの段落の書式差異を抽出し、Dictionaryで返す
‘ @param p1 比較元段落
‘ @param p2 比較先段落
Public Function CompareParagraphs(p1 As Paragraph, p2 As Paragraph) As Object
Dim diffs As Object
Set diffs = CreateObject(“Scripting.Dictionary”)

‘ フォント系の比較
Call CheckDifference(p1.Range.Font, p2.Range.Font, “Font.Name”, diffs)
Call CheckDifference(p1.Range.Font, p2.Range.Font, “Font.Size”, diffs)
Call CheckDifference(p1.Range.Font, p2.Range.Font, “Font.Bold”, diffs)

‘ 段落書式系の比較
Call CheckDifference(p1.Format, p2.Format, “Format.LeftIndent”, diffs)
Call CheckDifference(p1.Format, p2.Format, “Format.LineSpacing”, diffs)
Call CheckDifference(p1.Format, p2.Format, “Format.Style.NameLocal”, diffs)

Set CompareParagraphs = diffs
End Function

‘ @brief プロパティ値の差異を判定し、辞書に格納する汎用メソッド
Private Sub CheckDifference(obj1 As Object, obj2 As Object, propName As String, diffs As Object)
Dim val1 As Variant, val2 As Variant

‘ CallByNameでプロパティ名を動的に解決する
val1 = CallByName(obj1, Split(propName, “.”)(1), VbGet)
val2 = CallByName(obj2, Split(propName, “.”)(1), VbGet)

If val1 <> val2 Then
diffs.Add propName, “P1: ” & val1 & ” / P2: ” & val2
End If
End Sub

3. 堅牢な設計のための鉄則

1. 「CallByName」の活用

プロパティごとに `If p1.Font.Size <> p2.Font.Size Then…` と書くのは保守性の死を意味する。上記コードのように `CallByName` を用いることで、比較項目を配列で管理し、拡張性を確保せよ。

2. データベース連携時の注意点

もしこの差異情報をSQL ServerやSQLiteにログとして保存する場合、「比較対象のユニークID(または段落番号)」を必ず付与すること。Wordの段落は削除・挿入により番号が即座に変わる。Documentの `UniqueID` を利用するか、あらかじめ段落に `Bookmark` を埋め込んでおくのが、プロの品質管理における定石だ。

3. パフォーマンスの最適化

ドキュメント全体を走査する場合、`ScreenUpdating = False` は必須だが、さらに踏み込むなら `Range` オブジェクトのキャッシュ化を徹底すること。`Paragraph.Range` を何度も呼び出すのではなく、一度変数に格納してからプロパティにアクセスするだけで、実行時間は10倍以上改善する。

4. 結び:エンジニアとしての矜持

VBAは「古臭い言語」と揶揄されることもある。しかし、Wordのオブジェクトモデルという「巨大な迷宮」を論理の糸で解き明かす行為は、他のどの言語にも負けない高度なデータ構造の理解を必要とする。

今回紹介した差分解析ロジックは、単なるデバッグツールではない。それは「Wordの内部状態を可視化するレンズ」だ。これを使いこなせば、ユーザーから投げられる「なぜか書式が変わる」という曖昧な不具合報告に対し、客観的な事実(ファクト)をもって即座に回答できるようになるはずだ。

コードをコピペして満足するな。その背後にある「なぜWordがそう動くのか」という仕様の深淵に、常に思いを馳せてほしい。

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