Word VBAの深淵:ヘッダー・フッターを制する者は「ストーリー」を制する
Word VBAで「全置換」を実装しようとして、`ActiveDocument.Content.Find.Execute` だけを書いて満足していないか? もしそうなら、あなたのツールは致命的な欠陥を抱えている。
Wordという文書構造において、本文(Main Text)はあくまで「数あるストーリーの一つ」に過ぎない。ヘッダー、フッター、テキストボックス、脚注……これらはすべて別個の「ストーリー」として独立している。これらを無視した置換処理は、プロの現場では「バグ」と呼ばれる。
今日は、Wordのオブジェクトモデルを掌握し、文書内のあらゆるテキストを漏らさず狩り尽くすための「ストーリー横断型置換アルゴリズム」を伝授する。
—
1. なぜ `ActiveDocument.Content` だけでは足りないのか
Wordにおける `Range` オブジェクトは、文書内の特定の範囲を指し示すが、その範囲は「ストーリー」という閉じた空間に縛られている。
`ActiveDocument.Content` が指すのはメインの本文ストーリーのみだ。ヘッダーやフッター内のテキストを編集するには、それぞれに対応するストーリーレンジを取得し、明示的にループを回す必要がある。これを怠ると、「ヘッダーの会社名だけ旧姓のまま」といった恥ずかしいミスが確実に発生する。
—
2. プロダクション環境のための「ストーリー網羅」コード
以下のコードは、文書内の全ストーリー(`wdStoryTypes`)を列挙し、再帰的またはループ的に処理を行うための、極めて堅牢な設計だ。
Option Explicit
”’
”’
Public Sub ReplaceAllStories(ByVal findText As String, ByVal replaceText As String)
Dim rngStory As Range
Dim doc As Document
Set doc = ActiveDocument
‘ 画面更新を停止(パフォーマンス最適化:必須)
Application.ScreenUpdating = False
‘ 全ストーリータイプを巡回
For Each rngStory In doc.StoryRanges
‘ リンクされたストーリー(ヘッダー/フッターなど)を辿る
Do
‘ 実際の置換処理を実行
Call ExecuteReplace(rngStory, findText, replaceText)
‘ 次のリンクされたストーリーへ(連結されたテキストボックス等をケア)
Set rngStory = rngStory.NextStoryRange
Loop Until rngStory Is Nothing
Next rngStory
Application.ScreenUpdating = True
MsgBox “全ストーリーの置換が完了しました。”, vbInformation
End Sub
”’
”’
Private Sub ExecuteReplace(ByVal rng As Range, ByVal fText As String, ByVal rText As String)
With rng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = fText
.Replacement.Text = rText
.Forward = True
.Wrap = wdFindContinue ‘ 範囲を超えてループ
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = False
.Execute Replace:=wdReplaceAll
End With
End Sub
—
3. この設計が「堅牢」である理由
1. Do…Loop Until rngStory Is Nothing: Wordの文書構造において、メインストーリー以外のストーリーは「リンク」されている場合がある。特にテキストボックスを連結している場合、`NextStoryRange` を使ってチェーンを辿らなければ、途中で処理が途切れる。この実装は、その物理構造を忠実にトレースしている。
2. `Application.ScreenUpdating = False`: 100ページを超える文書でこれがないと、置換のたびに画面が再描画され、処理時間は数倍に跳ね上がる。プロは「ユーザーの待ち時間」もリソースとして管理する。
3. Findオブジェクトの初期化: `ClearFormatting` を行わないと、以前の検索条件(太字設定やフォント指定など)が残存し、意図しない挙動を引き起こす。`With rng.Find` 内で確実に環境をリセットするのが鉄則だ。
—
4. 実務への統合:データベース連携の注意点
もしあなたがExcelのリストからWordへ置換情報を流し込むようなツールを作っているなら、以下の点に留意せよ。
- 型定義の厳密化: 文字列の置換において、意図しない改行コードや特殊文字が含まれていないか、必ずバリデーションを挟むこと。
- エラーハンドリング: `On Error Resume Next` で誤魔化すのは素人のやることだ。置換対象がゼロの場合や、保護された文書(フォーム保護など)に遭遇した場合、VBAは容赦なくエラーを吐く。`Err.Number` をチェックし、ユーザーに状況をレポートする設計を組み込むべきだ。
- バックアップ戦略: 業務ツールであれば、処理前に `ActiveDocument.SaveAs2` で一時ファイルを生成するか、`UndoRecord` オブジェクトを使用して、処理を一括で「取り消し可能」な状態にすることを強く推奨する。
最後に
Word VBAは「泥臭い」と思われがちだが、オブジェクトモデルの深淵を理解すれば、これほど強力な自動化エンジンは他にない。
「動けばいい」コードを書くのは今日で卒業だ。君たちが書くコードが、他の誰かの数時間を、あるいは数日を救うことになる。その責任を胸に、今日も美しいコードを書いてほしい。
