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

スポンサーリンク

【Word VBA極限の知見】ワイルドカード検索で「特定の単語を含む段落全体」を瞬時にハイライトする堅牢な設計

Word VBAにおける`Find`オブジェクトの挙動は、多くの開発者を絶望の淵に追い込んできた。
「検索ヒットした文字列だけが選択される」「段落全体を着色したいのに、キーワード部分だけがハイライトされて終わる」「`Execute`のループで無限ループの罠にハマる」――。

日々の業務自動化において、「特定のキーワードが含まれる段落全体を網掛け・ハイライトする」という要求は非常に多い。しかし、これを直感だけでコードにすると、必ずと言っていいほど破綻する。

今回は、Wordのオブジェクトモデルの深層を知り尽くしたチーフアーキテクトの視点から、「ワイルドカード検索」と「Rangeの拡張(Expand)」を組み合わせ、実務の現場で絶対にバグらないプロダクションコードを授けよう。

1. なぜ「単純な検索と置換」では要件を満たせないのか?

Word VBAで文字を探す場合、大半の開発者は`Selection.Find`を使用する。これが諸悪の根源だ。
`Selection`オブジェクトを操作するアプローチは、画面の描画が発生して処理が劇的に遅くなるだけでなく、ドキュメントのカーソル位置に依存するため、バックグラウンド処理において致命的なバグの温床となる。

さらに、検索機能の本質は「文字列の検出」であって、「段落の選択」ではない。
ワイルドカードを使って `キーワード` のように検索しようものなら、Wordの非貪欲(ノン・グレディ。最短一致)の仕様に翻弄され、予期せぬ長大な範囲がマッチしたり、同一段落内で複数回ヒットして処理が重くなったりする。

プロフェッショナルな設計アプローチ

1. `Selection`を完全に排除し、`Range`オブジェクトで完結させる。(メモリ上で高速処理)
2. 検索はあくまで「キーワードの存在確認(起点の発見)」に徹する。
3. ヒットした瞬間に、その起点から`Range`を「段落(Paragraph)」単位に拡張する。
4. 重複着色や無限ループを防ぐためのポインタ制御を行う。

2. 実装のキモ:Rangeの拡張(`Expand`メソッド)

Word VBAの`Range`オブジェクトには、指定した単位(文字、単語、文、段落など)まで範囲を広げる `Expand` という強力なメソッドが存在する。

Dim rng As Range
Set rng = ActiveDocument.Content
‘ 検索で見つかった位置(rng)を段落全体に拡張する
rng.Expand wdParagraph

これだけで、キーワード単体のRangeが、そのキーワードを含んだ「段落全体のRange」に化ける。この特性を利用すれば、複雑なワイルドカードの構文で無理やり段落全体をマッチさせる必要がなくなるため、検索クエリを極めてシンプルに保つことができる。

3. 【プロダクションコード】堅牢なハイライト自動化マクロ

以下のコードは、実務の現場でそのままコピー&ペーストして即座に使える、エラーハンドリングとパフォーマンス最適化を極めた完全版のプロシージャだ。

Option Explicit

Public Sub HighlightParagraphsByKeyword()
‘ ==========================================
‘ 概要: 指定したキーワード(ワイルドカード可)を含む段落全体をハイライトする
‘ アーキテクト設計: 画面描画抑制、Rangeオブジェクトによる高速化、重複ヒット対策完備
‘ ==========================================

‘ 1. 設定パラメータ
Const SEARCH_KEYWORD As String = “【要確認】” ‘ 検索するキーワード
Const HIGHLIGHT_COLOR As WdColorIndex = wdYellow ‘ ハイライトの色

Dim doc As Document
Set doc = ActiveDocument

‘ 2. パフォーマンス最大化の呪文(画面描画と警告の停止)
With Application
.ScreenUpdating = False
.DisplayAlerts = wdAlertsNone
End With

On Error GoTo ErrorHandler

‘ 3. 検索範囲(Range)の初期化
Dim searchRange As Range
Set searchRange = doc.Content

‘ 4. Findオブジェクトの構築
With searchRange.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = SEARCH_KEYWORD
.Forward = True
.Wrap = wdFindStop ‘ 文書末尾で停止させる(ループ制御のため必須)
.Format = False
.MatchWildcards = False ‘ 必要に応じてTrueに変更(例: プレースホルダー検索など)

‘ 5. ループ処理による確実な全件捕捉
Do While .Execute
‘ 検索ヒットした瞬間のRangeを、段落単位(wdParagraph)に拡張
Dim targetRange As Range
Set targetRange = searchRange.Duplicate
targetRange.Expand wdParagraph

‘ 段落全体に対してハイライト適用
targetRange.HighlightColorIndex = HIGHLIGHT_COLOR

‘ 【重要】無限ループ回避のポインタシフト
‘ 検索Rangeの終端を、拡張した段落の終端に移動させ、次の検索を開始する
searchRange.Start = targetRange.End
searchRange.End = doc.Content.End

‘ ドキュメントの終端に達している場合はループを抜ける
If searchRange.Start >= doc.Content.End Then Exit Do
Loop
End With

‘ 6. 正常終了処理
Application.ScreenUpdating = True
MsgBox “処理が完了しました。”, vbInformation, “完了”
Exit Sub

ErrorHandler:
‘ 異常終了時のリカバリ
Application.ScreenUpdating = True
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
End Sub

4. コードの解説とアーキテクトのこだわり

① `ScreenUpdating = False` の徹底

Word VBAの処理速度を低下させる最大の原因は「GUIの再描画」である。数千行あるドキュメントでこれを怠ると、画面がチカチカと点滅した挙句、処理が数倍遅くなる。必ずエラーハンドラーとセットで制御すること。

② `searchRange.Duplicate` の使用

`Find.Execute` が成功すると、`searchRange` 自体は「ヒットしたキーワードの範囲」に縮小・変化する。これをそのまま `Expand` すると元の参照が狂う原因になるため、`Duplicate` メソッドを用いて安全なクローンRange操作を行っている。

③ 無限ループを絶対に防ぐポインタシフト

`Do While .Execute` を使う際、検索位置をずらす処理(`searchRange.Start = targetRange.End`)を忘れると、同じキーワードを永遠に検出し続ける無限ループ地獄に陥る。
Word VBA開発において、この「検索ポインタの適切な前方シフト」はマスト要件である。

5. データベースや外部ファイル連携への応用

このコードをベースにすれば、例えば「外部のExcelマスタやCSVファイルから検索ワードのリストを読み込み、合致する段落を動的に色分けしていくツール」へと簡単に拡張できる。

  • Excelから配列(Array)でキーワード群を取得し、`For Each` で上記の `SEARCH_KEYWORD` 部分を動的に差し替えてループを回す。
  • 処理ごとにハイライトの色(赤、黄、緑など)をステータスに応じて変更する。

実務で求められるのは、ただ動くコードではなく、「どれだけ巨大なファイルであってもメモリリークせず、高速かつ正確に完遂するロバストな設計」である。

Word VBAの限界を嘆く前に、まずはオブジェクトのスコープとライフサイクルを正しく支配することから始めよう。あなたの業務自動化スクリプトは、見違えるほど堅牢になるはずだ。

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