Word VBA「検索と置換」の深淵:実行時エラーを制圧する堅牢なアーキテクチャ
Word VBAにおける `Find` オブジェクトは、強力だが極めて気難しい。マクロ記録で生成されるコードをそのまま使うのは、時限爆弾を抱えて業務ツールを配布するようなものだ。
特に、ドキュメントの構造、保護設定、あるいはクリップボードとの競合によって引き起こされる「予測不能な実行時エラー」は、自動化ツールの信頼性を根底から覆す。今日は、現場で生き残るための「検索と置換のラッパー関数」の設計思想を伝授する。
—
1. なぜ「直書き」が失敗するのか
多くの開発者が書くコードはこうだ。
‘ 悪い例:エラーハンドリングが皆無
Selection.Find.Execute FindText:=”旧用語”, ReplaceWith:=”新用語”, Replace:=wdReplaceAll
これがなぜ危険か。
- 非表示の制約: 文書が保護されている場合、あるいは検索対象がテーブル内にあり構造が壊れている場合、即座にエラーが飛ぶ。
- 状態の汚染: `Find` オブジェクトはアプリケーション全体で共有される。「前の処理で設定されたワイルドカード設定」が次の処理に引き継がれ、意図しない挙動を起こす。
- UIの干渉: 検索結果がない場合や、途中で中断された場合、Wordのダイアログが前面に出てきて処理がハングする。
これらを防ぐには、「状態の初期化」「エラーの封じ込め」「事後処理の強制」の3層構造が必要だ。
—
2. 実装:堅牢なラッパー関数 `SafeReplace`
以下は、私が大規模なドキュメント修正プロジェクトで採用している共通モジュールのテンプレートだ。これをそのままコピーし、プロジェクトの標準ライブラリとして活用してほしい。
‘ @brief 検索と置換を安全に実行するラッパー関数
‘ @return Boolean 成功した場合はTrue、失敗した場合はFalse
Public Function SafeReplace( _
ByRef targetRange As Range, _
ByVal findText As String, _
ByVal replaceText As String, _
Optional ByVal matchWildcards As Boolean = False) As Boolean
Dim fnd As Find
Set fnd = targetRange.Find
‘ 1. Findオブジェクトの状態をクリーンにリセットする
fnd.ClearFormatting
fnd.Replacement.ClearFormatting
On Error GoTo ErrorHandler
With fnd
.Text = findText
.Replacement.Text = replaceText
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = matchWildcards
‘ 2. 実行と結果の判定
‘ Replace:=wdReplaceAll は戻り値を持たないため、実行結果を論理的に担保する
SafeReplace = .Execute(Replace:=wdReplaceAll)
End With
Exit Function
ErrorHandler:
‘ 3. エラーログの記録(必要に応じて外部ログファイルへ出力)
Debug.Print “Error [” & Err.Number & “]: ” & Err.Description
SafeReplace = False
‘ 安全な終了処理
Resume Next
End Function
—
3. 運用における「3つの鉄則」
コードを動かすだけでは不十分だ。エンジニアとして、以下の設計判断を忘れてはならない。
① 状態の隔離(Rangeオブジェクトの活用)
`Selection` を使うな。`Selection` はカーソル位置に依存するため、実行中にユーザーがマウスを触っただけでエラーになる。常に `ActiveDocument.Content` や指定した `Range` オブジェクトを引数として渡す設計にすること。これがマルチスレッドに近い安定感を生む。
② 正規表現(ワイルドカード)の罠
Wordのワイルドカードは、一般的なRegexとは仕様が異なる。特に `(` `)` のエスケープや、特殊文字の扱いは別物だ。複雑なパターンマッチングが必要な場合は、WordのFindで無理をせず、Word VBA内で正規表現エンジン(VBScript.RegExp)を呼び出し、置換後の文字列をセットするのが賢いエンジニアの選択だ。
③ 外部DB/ファイルとの連携
置換リストをExcelやCSVから読み込む場合、必ず「置換対象の文字数」と「Wordの制限」を確認すること。非常に長い文字列を `Replacement.Text` に突っ込むと、稀にWordが応答なしになる。この場合、`Selection` 経由での挿入ではなく、`Range.Text = …` による直接代入を検討せよ。
—
最後に:職人の矜持
自動化とは、単にコードを書くことではない。「エラーが発生したときに、いかにしてシステムを元の静寂な状態に戻すか」という、出口戦略の設計だ。
この `SafeReplace` を起点に、君たちのツールが「止まらない自動化」へと昇華することを期待している。エラーが出ないコードを書くのではない。エラーを飼い慣らすコードを書くのだ。
質問があれば、いつでも歓迎する。君のコードが、現場のストレスを一つでも減らすことを願っている。
