【Word VBA】Selectionに頼るな!Rangeオブジェクトで特定段落を高速かつ堅牢に太字にする極限の知見
Wordマクロの初学者が最初に陥る最大の罠、それは`Selection`(選択範囲)オブジェクトの乱用だ。
画面をチラチラとスクロールさせながら、カーソルを移動させて文字を太字にする……そんなコードを書いているとしたら、今すぐその手を止めてほしい。
実務におけるドキュメント自動化において、`Selection`は百害あって一利なしだ。描画処理のオーバーヘッドにより実行速度が致命的に低下し、ユーザーが誤ってマウスやキーボードに触れただけでマクロが暴走・クラッシュする。
今回は、Word VBAのプロフェッショナルたちが実践している、`Range`オブジェクトを用いた高速かつ堅牢な特定段落のピンポイント装飾の極意を伝授しよう。
—
1. なぜ「Range」でなければならないのか?
Wordのオブジェクトモデルにおいて、`Selection`は「今、ユーザーが見ている視覚的なカーソル位置」に依存する。これに対し、`Range実体`は「メモリ上に存在する目に見えないテキストの切り出し(アドレス)」だ。
- 速度の圧倒的差: 画面描画(ScreenUpdating)を伴わないため、処理速度は数十倍から数百倍に跳ね上がる。
- コンテキストの独立性: 文書を開いているビューの状態に依存しないため、バックグラウンド処理や巨大なドキュメントのバッチ処理でも絶対に破綻しない。
「特定のキーワードが含まれる段落だけを太字にする」という要件を、`Selection`で実装しようとすれば無限の苦悩が待っているが、`Range`と「ワイルドカード検索」を組み合わせれば、わずか数行の洗練されたコードで完結する。
—
2. 【プロダクションコード】実務でそのまま使える堅牢なマクロ
以下のコードは、単に動くだけのサンプルではない。エラーハンドリング、描画の抑止、オブジェクトのライフサイクル管理を考慮した、現場の第一線で使えるプロダクションクオリティのコードだ。
Option Explicit
Sub FormatSpecificParagraphs_Pro()
‘ =========================================================================
‘ 処理名: 指定キーワードを含む段落のピンポイント太字化
‘ 著者: シニアチーフアーキテクト
‘ 概要: Selectionを一切排除し、RangeのFind機能を用いて高速かつ安全に装飾を行う
‘ =========================================================================
Dim targetDoc As Document
Set targetDoc = ActiveDocument ‘ 処理対象ドキュメントの明示的な定義
Dim searchKeyword As String
searchKeyword = “【要確認】” ‘ ここに検索したいキーワードを指定
‘ — 1. パフォーマンス最適化の極意(描画・警告の完全抑制) —
With Application
.ScreenUpdating = False
.DisplayAlerts = wdAlertsNone
End With
Dim foundRange As Range
Set foundRange = targetDoc.Content
On Error GoTo ErrorHandler ‘ 予期せぬエラー時の安全装置
‘ — 2. Range.Findによる高速検索ループ —
With foundRange.Find
.ClearFormatting
.Text = searchKeyword
.Forward = True
.Wrap = wdFindStop ‘ 文書末尾に達したら検索を終了する
.MatchWholeWord = False
.MatchByte = False
.MatchWildcards = False
‘ 検索にヒットし続ける限りループ
Do While .Execute
‘ ★ここが核心:ヒットしたテキストそのものではなく、「段落(Paragraph)」全体をRangeとして取得する
Dim targetParaRange As Range
Set targetParaRange = foundRange.Paragraphs(1).Range
‘ — 3. 厳格な書式設定 —
‘ 段落末尾の改行文字(ParagraphMark)まで太字にならないよう、長さを調整する場合もあるが
‘ 今回は段落全体をシンプルに太字にする
targetParaRange.Font.Bold = True
‘ 次の検索開始位置を、現在のヒット箇所の末尾に移動(無限ループの防止)
foundRange.Collapse wdCollapseEnd
Loop
End With
ErrorHandler:
‘ — 4. 確実なリソース解放と環境復元 —
With Application
.ScreenUpdating = True
.DisplayAlerts = wdAlertsAll
End With
If Err.Number <> 0 Then
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “処理中断”
Else
MsgBox “指定キーワードを含む段落の太字化が完了しました。”, vbInformation, “処理成功”
End If
End Sub
—
3. コードの急所とアーキテクトの解説
このコードがなぜ「プロ仕様」なのか、3つのポイントで解説する。
① `foundRange.Paragraphs(1).Range` という魔法
`Find`メソッドでヒットするのは、あくまで「キーワードの文字列そのもの」のRangeだ。しかし私たちが求めているのは「そのキーワードが含まれる段落全体」の装飾である。
`foundRange.Paragraphs(1).Range` と記述することで、ヒットした位置が属する段落オブジェクトを瞬時に取得し、その範囲をごっそりRangeとして再定義している。これがオブジェクト指向Word VBAの醍醐味だ。
② 無限ループを防ぐ `Collapse`
検索系処理で最も恐ろしいのは、同じ位置でヒットし続け、マクロがフリーズする「無限ループ地獄」だ。
`.Execute` が成功した直後、`foundRange.Collapse wdCollapseEnd` を実行して検索開始位置を「ヒットしたブロックの末尾」に強制的に進めている。これにより、二重検知を完全に防いでいる。
③ 徹底的な環境復元(トランザクション的思考)
`Application.ScreenUpdating = False` で画面描画を止めたら、処理が成功しようが失敗しようが、必ず元の状態に戻さなければならない。
`On Error GoTo ErrorHandler` を経由させて、エラー時であっても確実に `ScreenUpdating = True` が実行される堅牢な構造(try-finallyパターンのVBA的実装)を担保している。実務ツールにおいて、Wordをフリーズさせたまま強制終了させるリスクを残すことは許されない。
—
4. データベース・外部ファイル連携への発展を見据えて
今回はハードコードしたキーワードを検索したが、実務の現場では、このキーワードリストをExcelファイルや外部データベース(SQL Server / SQLite等)から動的に読み込むアーキテクチャに拡張することになる。
その際も、今回構築した「`Range` オブジェクトをベースにした非選択型エンジン」の骨組みさえできていれば、配列やDictionaryに格納したキーワード群を `For Each` で回して `searchKeyword` に代入するだけで、そのまま企業向けの強力な自動化ツールへとスケールさせることができる。
「画面を触らせず、裏で一瞬にしてドキュメントを組み上げる」。
このマインドセットを身につけた瞬間から、あなたのVBAコードは“おもちゃ”から“プロフェッショナルなシステム”へと進化する。ぜひ、現場の業務効率化に役立ててほしい。
