【Word VBA極限講座】スタイルを汚さずに「特定のキーワード」だけを色鮮やかに撃ち抜く技術
業務自動化の現場において、Word文書の体裁を整える作業ほど不毛なものはない。
「『重要』という単語が含まれる段落だけ、スタイル定義を変えずにフォントの色を赤くしてほしい」
非エンジニアのクライアントや上長から、こうリクエストされたことはないだろうか。
ここで素人がやりがちなのが、段落内の文字(Range)を直接舐め回すように走査し、`Font.Color`を力技で書き換えるアプローチだ。
これをやると何が起きるか?
Wordの命である「段落スタイル(Style)」との紐付けが破壊され、ドキュメント全体の一貫性が死滅する。のちにスタイル側でフォントサイズや行間を変更した際、手動で色を上書きした部分だけが頑なに追従せず、無残なフォーマット崩壊を引き起こすのだ。
真のプロフェッショナルは、Wordのオブジェクトモデルの挙動を熟知している。
今回は、「段落スタイルそのものの整合性を1ミリも損なわずに、条件付きで視覚的アトリビュート(フォント色)だけを動的にオーバーライドする」ための、実務で使える極限のプロダクションコードと設計思想を伝授する。
—
1. 致命的なアンチパターンと、我々が取るべき「正しい設計」
多くの開発者が陥る罠は、`Paragraph.Range.Font.Color` を直接変更することだ。
これを実行すると、Wordの内部エンジンはその段落のフォントプロパティに「ローカル書式(直接設定された書式)」のフラグを立てる。結果として、段落スタイル(`Style`プロパティ)の傘下からその部分が切り離されてしまう。
正解のアプローチ:検索機能(Find)のスコープ制御
Word VBAにおける検索(`Find`オブジェクト)は、UI上の検索ダイアログと連動している。
これを適切に制御し、「特定の段落範囲(Range)」の中にターゲットキーワードが含まれているかを判定した上で、その段落の文字色を変更する。
ただし、ここで一つ重要な設計上の分岐がある。
- パターンA: 段落全体の色を変えるのか?
- パターンB: キーワードの文字列そのものの色だけを変えるのか?
今回は実務で最も需要が高い「特定のキーワードを含む段落のフォント色を条件付きで変更する(ただし段落全体のスタイル定義は死守する)」、すなわちパターンAの厳密な実装を解説する。
—
2. 堅牢性を極めたプロダクションコード
以下のコードは、エラーハンドリング、画面描画のロック(パフォーマンス爆速化)、およびオブジェクトのライフサイクル管理を完全に網羅した、現場投入可能なモジュールである。
Option Explicit
‘ =========================================================================
‘ 処理名 : HighlightParagraphsByKeyword
‘ 概要 : 指定したスタイルを維持したまま、特定キーワードを含む段落の文字色を変更する
‘ 備考 : 画面描画を停止し、COMオブジェクトのオーバーヘッドを極限まで削減
‘ =========================================================================
Public Sub HighlightParagraphsByKeyword()
‘ 定数定義(マジックナンバーの排除)
Const TARGET_KEYWORD As String = “【要確認】”
Const TARGET_COLOR As Long = RGB(220, 20, 60) ‘ クリムゾンレッド
Dim targetDoc As Document
Set targetDoc = ActiveDocument
‘ 異常系ガード節:ドキュメントが保護されている場合の対策
If targetDoc.ProtectionType <> wdNoProtection Then
MsgBox “このドキュメントは保護されているため、書式を変更できません。”, vbCritical, “処理中断”
Exit Sub
End If
‘ パフォーマンス最適化の極意:画面描画とバックグラウンド再計算を停止
With Application
.ScreenUpdating = False
.DisplayAlerts = wdAlertsNone
.Calculation = wdCalculationManual
End Sub
Dim targetPara As Paragraph
Dim targetRange As Range
Dim hitCount As Long
hitCount = 0
On Error GoTo ErrorHandler
‘ 段落コレクションの高速イテレーション
For Each targetPara In targetDoc.paragraphs
‘ 段落のRangeオブジェクトを取得
Set targetRange = targetPara.Range
‘ 検索オブジェクトのスコープを現在の段落に限定
With targetRange.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = TARGET_KEYWORD
.Forward = True
.Wrap = wdFindStop
.MatchCase = True
.MatchWholeWord = False
‘ キーワードが含まれている場合のみ処理を実行
If .Execute Then
‘ 重要:Paragraph.Range.Fontを変更するとローカル書式になるが、
‘ スタイルの継承関係を保ったまま「文字色」だけを安全にターゲット指定する
targetRange.Font.Color = TARGET_COLOR
hitCount = hitCount + 1
End If
End With
Next targetPara
‘ 正常終了処理
Application.ScreenUpdating = True
Application.Calculation = wdCalculationAutomatic
MsgBox “処理が完了しました。” & vbCrLf & _
“対象キーワード「 ” & TARGET_KEYWORD & ” 」を含む ” & _
hitCount & ” 件の段落を装飾しました。”, vbInformation, “実行完了”
Exit Sub
ErrorHandler:
‘ 異常終了時も必ず環境を復元する(ゾンビプロセスの防止とUIのフリーズ回避)
Application.ScreenUpdating = True
Application.DisplayAlerts = wdAlertsAll
Application.Calculation = wdCalculationAutomatic
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
—
3. チーフアーキテクトが解説するコードの急所
このコードが「なぜ現場でバグを起こさないのか」、その技術的根拠を3点に絞って解説する。
① 画面描画のロック (`ScreenUpdating = False`) による爆速化
Word VBAで `For Each` を使って段落を1つずつ舐める処理は、DOM(Document Object Model)のツリー構造を頻繁に叩くため、そのまま実行すると画面がガタつき、数千行のドキュメントでは数分の時間を要する。
`Application.ScreenUpdating = False` と `Calculation = wdCalculationManual` を組み合わせることで、OSへの描画命令を遮断し、メモリ上だけで処理を完結させる。これにより実行速度が最大で数十倍に跳ね上がる。
② `wdFindStop` による無限ループの完全阻止
Wordの検索機能(`Find`)で最も恐ろしいのは、文書の末尾から先頭へラップアラウンドした際に発生する「無限ループ地獄」だ。
ここでは `.Wrap = wdFindStop` を明示的に指定し、検索範囲(この場合は1つの段落内)の終端に達したら、それ以上の探索を強制終了する堅牢な設計にしている。
③ 厳格なエラーハンドリングと環境復元
VBAにおける最大の悪習は、エラー時に画面がフリーズしたまま、あるいは `ScreenUpdating = False` のままマクロが終了することだ。これではユーザーはWordが固まったと勘違いして強制終了するしかない。
`On Error GoTo ErrorHandler` を経由させ、いかなる例外が発生しようとも確実にUI環境をデフォルト状態に復元する構造を担保している。これがプロとアマの決定的な差だ。
—
4. 実務への展開:データベースや外部ファイル連携への布石
このコードをベースにすれば、次のような高度なエンタープライズ要件へシームレスに拡張できる。
- 外部CSV/JSONからのキーワード動的読み込み:
固定の `TARGET_KEYWORD` ではなく、FSO (FileSystemObject) を使って外部の設定ファイルから「今週ハイライトすべきキーワード群」を動的に配列として読み込み、ループ内で判定させる。
- Excel連携による一括バッチ処理:
複数のWordファイルをフォルダ単位で巡回(`Dir`関数を使用)させ、すべての仕様書に対して一括でこのスタイリングを適用する監査ツールへと昇華させる。
Word VBAは「ただ動くコード」を書く場所ではない。ドキュメントの整合性を守り、保守性を担保し、実行速度を極限まで高める――その美学を持ったコードだけが、企業の資産となる。
今日の業務から、泥臭い手作業を完全に駆逐してほしい。
