【実務・中級編】【上級者向け】正規表現による「数式エディタ」内の文字列検索と置換の限界と回避策 – Word VBA解析バイブル

スポンサーリンク

Word VBAの深淵:数式エディタ(OMath)の「見えない壁」を突破するXMLハック

WordのVBAで業務を自動化していると、必ず突き当たる「鉄の壁」がある。それが数式エディタ(OMath)だ。

`Selection.Find` や `Range.Find` を駆使しても、数式の中に埋め込まれた変数は一切ヒットしない。Wordのドキュメントモデルにおいて、数式は「非表示のオブジェクト」というより、「独立した別世界」として管理されているからだ。

今回は、この「数式内の文字列」を正規表現で制御するための、現場レベルの極限解法を伝授する。

—

なぜ `Find` は数式を無視するのか?

Wordの検索エンジンは、`StoryType`が `wdMainTextStory`(本文)である場合、`OMath` オブジェクトの中身をテキストとして解釈しない。`OMath` は専用のXML(OMML: Office Math Markup Language)で記述されており、VBAの標準的な検索機能はこのレイヤーを貫通できない。

これを力技で解決する方法はただ一つ。WordのOpenXMLを直接操作し、数式内のテキストノードを正規表現で置換した後に、ドキュメントに再反映させることだ。

—

堅牢な設計へのアプローチ

直接 `OMath` を操作するのではなく、以下の手順を踏むのが「バグらせない」ための唯一の道だ。

1. XMLへの変換: `Range` オブジェクトを一旦 `WordML` 形式で抽出する。
2. メモリ内処理: `VBScript.RegExp` オブジェクトでメモリ上で置換を行う。
3. 再注入: 置換後のXMLを `Range` に戻す。

注意点:ファイル連携とパフォーマンス

  • Undoスタックの肥大化: 大量置換を行う際は、必ず `Application.UndoRecord` で処理をラップし、処理後にメモリ解放を行うこと。
  • XMLの構造破壊: `OMML` はXML構造が崩れるとWordファイル自体が破損する。正規表現でタグ(例: `…`)を破壊しないよう、慎重なパターン設計が求められる。

—

【プロダクションコード】数式内文字列置換エンジン

以下は、数式内の特定の変数を一括置換するための汎用関数だ。

‘ 参照設定: Microsoft VBScript Regular Expressions 5.5
Public Sub ReplaceTextInOMath(targetRange As Range, pattern As String, replaceText As String)
Dim xmlContent As String
Dim regEx As Object

‘ 1. 数式を含む範囲をWordML形式で取得
xmlContent = targetRange.XML

‘ 2. 正規表現エンジンのセットアップ
Set regEx = CreateObject(“VBScript.RegExp”)
With regEx
.Global = True
.IgnoreCase = False
.MultiLine = True
‘ 数式のテキストノード()の中身をターゲットにする
‘ 注意: OMMLの構造を壊さないよう、タグの内側だけを狙う
.pattern = “()” & pattern & “()”
End With

‘ 3. メモリ上で置換実行
If regEx.Test(xmlContent) Then
xmlContent = regEx.Replace(xmlContent, “$1” & replaceText & “$2”)

‘ 4. 置換後のXMLをドキュメントに反映
targetRange.InsertXML xmlContent
End If

Set regEx = Nothing
End Sub

‘ 使用例
Public Sub Example_ProcessEquations()
‘ ドキュメント内の全数式オブジェクトを対象にする
Dim oMath As OMath
For Each oMath In ActiveDocument.OMaths
Call ReplaceTextInOMath(oMath.Range, “x”, “y”) ‘ 数式内の x を y に置換
Next oMath
End Sub

—

なぜこの実装が「極限」なのか

1. `InsertXML` の活用: 単なる文字列操作ではなく、WordのネイティブなXMLインポート機能を使うことで、数式のレイアウト情報を損なわずに更新できる。
2. 正規表現の制約: `()` をキャプチャグループに含めることで、タグ自体を削除する事故を完全に防いでいる。
3. スケーラビリティ: `targetRange` を受け取る設計にしているため、ドキュメント全体だけでなく、選択範囲や特定のセクションに限定した処理も容易だ。

最後に:エンジニアとしての忠告

数式内の置換は、いわば「外科手術」だ。もし置換対象が複雑な構造(例:分数や積分記号の中にある変数)であれば、この正規表現アプローチでも限界が来る。その場合は、`MSXML2.DOMDocument` を使用し、ノードツリーをトラバースして純粋なテキストノードのみを書き換える「DOM解析アプローチ」へ移行せよ。

しかし、まずはこのXML置換で十分なはずだ。業務自動化において最も重要なのは「完璧なツールを作ること」ではなく、「確実にエラーを回避し、工数を削減できるツールを、保守可能なコードで提供すること」にある。

君のコードが、数式という「魔境」を攻略する一助となれば幸いだ。

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