【実務・中級編】【中級者向け】検索結果のRangeを配列に格納し、置換後に「ハイライト」を一括適用する手法 – Word VBA解析バイブル

スポンサーリンク

Word VBAで「検索と置換」を極める:Rangeの配列キャッシュによる高速化と堅牢な書式制御

Word VBAの `Find` オブジェクトを使い、ループの中でいちいち `Execute` を発行して書式を変更していないだろうか?もしそうなら、あなたのコードはWordのレンダリングエンジンに対して、過剰な負荷を強いていることになる。

大規模文書において、検索のたびに `Selection` を動かしたり、逐次的にオブジェクトへアクセスしたりする手法は、処理速度を低下させるだけでなく、予期せぬ「カーソル位置のズレ」によるバグの温床だ。

本記事では、検索結果を `Range` オブジェクトの配列に一時格納し、最後にまとめてプロパティを操作する「一括処理アーキテクチャ」を伝授する。これができれば、Word自動化のレベルが一段階上がるはずだ。

—

なぜ「逐次処理」は悪手なのか

`Find.Execute` を実行するたび、Wordはドキュメント内を探索し、対象が見つかれば `Range` を更新する。このループ内で `Replacement.Font` などを操作すると、Wordは都度レイアウトの再計算を試みる可能性がある。

  • 非効率なプロセス: `検索 -> 選択 -> 書式変更 -> 再描画` の無限ループ。
  • リスク: 処理中のエラーで `Selection` が意図しない場所に取り残される。
  • 解決策: 「検索(情報の抽出)」と「置換/装飾(情報の書き込み)」を完全に分離する。

—

実装:Range配列による一括処理プロトタイプ

以下のコードは、指定した文字列を検索し、その `Range` を配列にキャッシュしてから、最後にハイライトを適用するテンプレートだ。

Option Explicit

”’

”’ 高速な検索と書式一括適用を行うメインプロシージャ
”’

Public Sub ApplyHighlightToSearchMatches()
Dim doc As Document: Set doc = ActiveDocument
Dim rng As Range
Dim matches() As Range
Dim matchCount As Long

‘ 配列の動的確保
ReDim matches(0 To 0)

‘ 検索の初期化
Set rng = doc.Content
With rng.Find
.ClearFormatting
.Text = “対象文字列” ‘ ここに検索ワード
.Forward = True
.Wrap = wdFindStop
.Format = False

‘ 検索ループ:Rangeオブジェクトのみを抽出して配列へ退避
Do While .Execute
If matches(0) Is Nothing Then
Set matches(0) = rng.Duplicate
Else
matchCount = matchCount + 1
ReDim Preserve matches(0 To matchCount)
Set matches(matchCount) = rng.Duplicate
End If
‘ 検索範囲を次へ移動(無限ループ防止)
rng.Collapse wdCollapseEnd
Loop
End With

‘ 配列に格納されたRangeに対して一括で処理を行う
If Not matches(0) Is Nothing Then
Application.ScreenUpdating = False ‘ 描画停止による高速化

Dim i As Long
For i = LBound(matches) To UBound(matches)
‘ ここで書式を変更(ハイライト)
matches(i).HighlightColorIndex = wdYellow
Next i

Application.ScreenUpdating = True
End If

MsgBox matchCount + 1 & ” 件のハイライト処理が完了しました。”, vbInformation
End Sub

—

プロフェッショナルが守るべき3つの設計原則

1. `.Duplicate` による範囲のクローン

`Find` オブジェクトが返す `Range` は、検索のたびに動的に変化する。配列に格納する際は必ず `.Duplicate` を使用すること。これを行わないと、配列内のすべての要素が「最後に検索された場所」を指すという、VBA特有の参照バグに陥る。

2. `ScreenUpdating` の厳密な制御

処理前後の `Application.ScreenUpdating = False / True` は必須だ。ただし、エラーハンドリングを怠ると、万が一処理が中断した際に画面が真っ白のまま更新されなくなる。必ず `On Error GoTo` でエラー発生時も `ScreenUpdating = True` を呼び出す構成にすること。

3. データベース/外部ファイル連携時の注意

もし検索キーワードを外部のExcelやCSVから読み込む場合、読み込みと検索は完全に分離せよ。外部リソースへのアクセスは低速であるため、一度メモリ上のコレクションに格納してから、Word側の検索プロセスを回すのが鉄則だ。

—

結び:コードは「状態」を管理するためにある

Word VBAにおいて、「何をどこまで操作したか」という状態を `Selection` に頼る開発者は二流だ。`Range` オブジェクトという「独立した領域」を配列で管理する手法は、複雑なドキュメント修正においても極めて高い堅牢性を発揮する。

次のプロジェクトでは、ぜひ「検索と装飾の分離」を実装してみてほしい。Wordが軽快に動く様を目の当たりにすれば、もう以前の逐次処理には戻れなくなるはずだ。

技術は、書く側の「思考の解像度」で決まる。君の自動化ツールが、現場を救う強力な武器になることを期待している。

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