Word VBAの「Find」を支配せよ:ワイルドカード置換による非破壊的・高速な文字列入れ替え術
Word VBAを扱う多くのエンジニアが、`Find.Execute`の挙動に翻弄され、ループ処理で泥沼にハマっているのを見る。特に「文字列の入れ替え」が必要な時、`Range`を操作して切り貼りするのは素人のやり方だ。
Wordの検索エンジンが持つ「ワイルドカード」と「グループ化」の機能を掌握すれば、数十万文字のドキュメントであっても、一瞬で、かつメモリ負荷を最小限に抑えて構造を書き換えることができる。
今回は、実務で頻出する「特定の単語の直前にある単語を入れ替える」という課題を例に、プロダクションレベルの堅牢な実装手法を伝授する。
—
1. なぜ「力技のループ」が地雷なのか
初心者がやりがちなのは、`Selection`オブジェクトを動かしてループさせるコードだ。
- 画面更新の遅延: `ScreenUpdating`をオフにしても、オブジェクトの選択はWordのGUIエンジンに負荷をかける。
- イベントの競合: 選択範囲が変わるたびにイベントが発生し、意図しない挙動やメモリリークを招く。
真のエンジニアは、「Rangeオブジェクトを固定し、メモリ内で検索エンジンを走らせる」。これがWord VBAの鉄則だ。
—
2. ワイルドカードによる「順序の入れ替え」の極意
Wordのワイルドカード検索では、括弧 `()` で囲んだ範囲を「グループ」として認識し、置換文字列で `\1`, `\2` と呼び出せる。
例えば、「A B」を「B A」にしたい場合:
- 検索する文字列: `(<>) (<>)`
- 置換後の文字列: `\2 \1`
この一行で、ドキュメント全体の構造を論理的に書き換える。これが爆速の秘訣だ。
—
3. 実装:堅牢なプロダクションコード
以下のコードは、単に動くだけではない。エラーハンドリング、Undo処理のブロック、そしてパフォーマンスの最適化を考慮した設計だ。
‘ @brief 特定のパターン(単語1 単語2)を(単語2 単語1)に置換する
‘ @param targetRange 対象とする範囲(Document全体でも可)
Public Sub SwapAdjacentWords(ByRef targetRange As Range)
‘ 処理の高速化と安定化
Application.ScreenUpdating = False
Dim fnd As Find
Set fnd = targetRange.Find
‘ オブジェクトの初期化(前回の設定を引き継がないための防御)
With fnd
.ClearFormatting
.Replacement.ClearFormatting
‘ 検索設定:ワイルドカードをオンにする
.Text = “(<[A-Za-z]@>) (<[A-Za-z]@>)”
.Replacement.Text = “\2 \1”
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True ‘ ここが重要
‘ 一括実行(ReplaceAllは高速だが、慎重な設計が必要)
.Execute Replace:=wdReplaceAll
End With
Application.ScreenUpdating = True
End Sub
コードの解説
- `.ClearFormatting`: これを忘れると、以前の検索設定が残存し、予期せぬバグを引き起こす。どんな時も「無」から始めるのが鉄則だ。
- `(<[A-Za-z]@>)`: `[A-Za-z]@` は「アルファベット1文字以上」を表す。`()`で囲むことで、置換時にグループとしてキャプチャする。
- `wdFindContinue`: 指定した範囲の末尾に達した時、ドキュメントの先頭に戻って検索を継続させる設定だ。
—
4. プロフェッショナルとしての注意点
この手法を実務で採用する際、以下の3点には特に注意を払ってほしい。
1. 正規表現の限界: Wordのワイルドカードは、標準的なRegex(Perl互換など)とは仕様が異なる。特に「否定」や「最小一致」の挙動は独特だ。複雑すぎるパターンは、分割して実行することを推奨する。
2. データベース連携時の正規化: Word文書からデータを抽出し、SQL Server等へ流し込む場合、Wordのワイルドカードで「整列(正規化)」してからエクスポートすると、後続のデータクレンジング工程が劇的に楽になる。
3. Undo(元に戻す)の設計: `ReplaceAll` を実行すると、置換作業全体が一つの履歴として保存される。ユーザーが誤操作した際の被害を最小化するため、必要に応じて `UndoRecord` を用いたトランザクション管理を検討せよ。
まとめ:ツールは「書く」のではなく「設計する」
「動けばいいコード」を書くエンジニアは、数年後のメンテナンスで必ず苦しむ。
今回紹介したような、Wordの検索エンジンを直接操作する設計は、コード量を最小限に抑え、処理速度を最大限に引き出す。
君が作るツールが、単なる作業補助ではなく、組織の業務プロセスを支えるインフラになることを期待している。さあ、次はどのロジックを最適化する?
