【テクニカル・上級編】【中級者向け】ワイルドカード検索で「特定の単語を含む段落全体」をハイライトする – Word VBA解析バイブル

スポンサーリンク

検索の「点」を段落の「面」へ変える:Word VBAにおけるRange拡張の技術的真髄

Word VBAにおいて、`Find`オブジェクトは単なる文字列検索の道具ではない。それは、ドキュメントという広大なメモリ空間を操作するための、極めて強力かつ「危険な」ポインターである。

多くの開発者が`Find.Execute`で満足しているが、真のアーキテクトは「検索結果そのもの」には興味がない。重要なのは、そのマッチングした地点を起点として、どのように`Range`を拡張し、ドキュメントの論理構造(段落)を正しくハンドリングするかにある。

今回は、特定の単語を含む「段落全体」をハイライトするという、一見単純だが奥深いタスクを通じて、Wordのメモリ管理とオブジェクト操作の深淵に触れていこう。

1. なぜ「Rangeの拡張」が鬼門なのか

VBAで`Selection`を多用するコードは、低級なプログラミングの典型だ。画面描画を伴う`Selection`は極めて低速であり、大規模ドキュメントではフリーズの原因となる。

我々が操作すべきは常に`Range`オブジェクトである。しかし、`Find`でヒットした`Range`は、あくまで「検索対象の文字列」を指し示すに過ぎない。これを段落全体へ拡張するには、`Range.Expand`メソッドを用いる。

実装の極意:プロフェッショナルな検索ロジック

以下に、メモリ効率と堅牢性を両立させた実装を示す。

‘ @brief 特定のキーワードを含む段落全体をハイライトする
‘ @param targetWord 検索対象の文字列
‘ @param highlightColor ハイライトの色(WdColor)
Public Sub HighlightParagraphContaining(ByVal targetWord As String, ByVal highlightColor As WdColor)
Dim doc As Document
Dim rng As Range

Set doc = ActiveDocument
Set rng = doc.Content

‘ 画面描画を停止し、処理速度を極限まで引き上げる
Application.ScreenUpdating = False

With rng.Find
.ClearFormatting
.Text = targetWord
.Replacement.Text = “”
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True ‘ ワイルドカードを有効化

Do While .Execute
‘ ヒットしたRangeを段落単位へ拡張する
rng.Expand Unit:=wdParagraph

‘ ハイライトを適用
rng.HighlightColorIndex = highlightColor

‘ 次の検索のためにRangeを移動(無限ループ回避の要)
rng.Collapse Direction:=wdCollapseEnd
Loop
End With

‘ 描画を復旧し、メモリを解放
Application.ScreenUpdating = True
Set rng = Nothing
Set doc = Nothing
End Sub

2. アーキテクトの視点:なぜこのコードが「強い」のか

このコードには、現場で生き残るための3つの「知見」が込められている。

① `wdCollapseEnd` の重要性

`Find`が成功した後、`rng`は検索された単語を囲んでいる。そのままループを回すと、検索がその単語で止まり、無限ループに陥るか、不完全な動作を引き起こす。`rng.Collapse Direction:=wdCollapseEnd` を呼ぶことで、Rangeを「検索した単語の直後」に収束させ、次の検索を正確に開始させる。これが「検索の作法」だ。

② `Application.ScreenUpdating` の強制制御

WordのObject Modelは、UIと密接に結合している。大規模なドキュメントで`Range`を操作する際、画面更新をオンにしたままだと、OSのレンダリングエンジンが悲鳴を上げる。必ずオフにし、処理終了後に戻す。これは自動化における「礼儀」である。

③ オブジェクトの明示的解放(Disposeに近い感覚)

VBAはガベージコレクションが優秀ではない。特にWordの`Range`や`Document`は、参照カウントが保持され続けると、Wordを閉じた後もプロセスがゾンビとして残り続ける原因となる。`Set rng = Nothing` は単なる儀式ではなく、リソースリークを防ぐ防波堤だ。

3. 次のステージへ:正規表現とWindows APIの活用

もし、より複雑なパターンマッチング(例えば「特定のキーワードが含まれ、かつ特定の書式が適用されている段落」など)が必要なら、標準の`Find`では力不足だ。

その場合、私はVBScript.RegExpオブジェクトをVBAから呼び出し、マッチング位置を特定した後に`doc.Range(start, end)`でWord側のRangeを再定義する手法を推奨する。

また、Wordの処理が重すぎて非同期処理を行いたい場合、Windows APIの`Sleep`を呼び出してCPUの負荷をコントロールすることもある。だが、まずは「Wordの内部的なRange制御をいかに正確に行うか」をマスターすること。これが全ての自動化の根幹である。

最後に

Word VBAは、現代のローコードツールがどれだけ進化しても、ドキュメントの深部を操作できる唯一無二の手段であり続ける。`Find`を制する者は、ドキュメントの構造を制する。今日から、`Selection`を捨て、`Range`を支配するエンジニアへと脱皮してほしい。

それが、我々レガシーを愛するアーキテクトの矜持だ。

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