【Word VBA極意】「目立つ警告」を自動生成せよ:段落解析による動的書式設定のアーキテクチャ
Word VBAで「特定のキーワードが含まれる段落を枠線で囲む」という要件、一見すると簡単そうに見えるだろう。しかし、これを「なんとなく動くコード」で実装すれば、たちまちドキュメントの破壊や、数千ページ規模の文書での劇的なパフォーマンス低下を招く。
私はこれまで、数百の企業でマクロの再構築を行ってきた。その経験から断言する。Wordオブジェクトモデルへのアクセスは「コスト」であると意識せよ。
今日は、プロフェッショナルとして恥ずかしくない、堅牢で拡張性の高い「段落強調エンジン」の設計思想とコードを伝授する。
—
なぜ「愚直なループ」は死を招くのか
多くの初心者が陥る罠は、`For Each` ループの中で、毎回 `Selection` を動かしたり、`Paragraph.Range.Font` プロパティを個別に何度も叩くことだ。
1. Selectionの排除: `Selection` は画面描画を伴うため極めて低速だ。常に `Range` オブジェクトを直接操作せよ。
2. 画面更新の制御: `Application.ScreenUpdating` を制御しないのはエンジニアとして怠慢である。
3. オブジェクトのキャッシュ: 繰り返し参照するプロパティは変数に退避させる。これがメモリ管理の基本だ。
—
プロダクションコード:High-Performance Paragraph Highlighter
以下のコードは、単に動くだけではない。エラーハンドリングと処理効率を考慮した、実戦投入レベルの設計だ。
Option Explicit
”’
”’
Public Sub HighlightKeywordsByBorder()
Dim doc As Document
Dim para As Paragraph
Dim targetWords As Variant
Dim i As Long
‘ 処理対象のキーワードリスト
targetWords = Array(“警告”, “注意”, “重要”)
Set doc = ActiveDocument
‘ 画面更新停止:描画コストを抑え、処理速度を劇的に向上させる
Application.ScreenUpdating = False
On Error GoTo Cleanup
For Each para In doc.Paragraphs
‘ 空行や無意味な段落はスキップし、リソースを節約
If Len(Trim(para.Range.Text)) > 1 Then
For i = LBound(targetWords) To UBound(targetWords)
If InStr(para.Range.Text, targetWords(i)) > 0 Then
Call ApplyParagraphBorder(para)
Exit For ‘ 一致した時点で次へ
End If
Next i
End If
Next para
Cleanup:
Application.ScreenUpdating = True
If Err.Number <> 0 Then MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical
End Sub
”’
”’
Private Sub ApplyParagraphBorder(ByRef para As Paragraph)
With para.Range.ParagraphFormat.Borders(wdBorderLeft)
.LineStyle = wdLineStyleSingle
.LineWidth = wdLineWidth050pt
.Color = wdColorRed
End With
‘ 四方を囲む場合は .Borders(wdBorderRight) 等を追記
‘ 重要なのは、プロパティを個別に設定すること
para.Range.ParagraphFormat.Borders.Enable = True
End Sub
—
アーキテクトの視点:堅牢性を高める3つのポイント
1. 範囲操作の分離(Separation of Concerns)
`ApplyParagraphBorder` を別プロシージャに切り出しているのは理由がある。将来、「枠線だけでなく、背景色も変えたい」「フォントを太字にしたい」という要件追加が来た際に、メインのループを汚さずに拡張するためだ。これが「保守性の高いコード」の正体である。
2. 画面更新の制御は必須
`Application.ScreenUpdating = False` を忘れると、Wordはループのたびにレイアウトを再計算する。数ページなら良いが、100ページを超えた瞬間、あなたのPCは「応答なし」の地獄を見ることになる。必ず `Cleanup` ラベルを用意し、エラー時でも必ず画面更新をONに戻す設計にしておくこと。
3. データ連携への布石
もしこれが「外部CSVからキーワードを読み込む」要件へと進化する場合、`targetWords = Array(…)` を `FileSystemObject` を使った外部読み込み関数に差し替えるだけで対応できる。ハードコーディングを避ける設計が、君を将来の残業から救うことになるだろう。
—
結論:コードは「書く」ものではなく「育てる」ものだ
今回提供したコードは、単なる機能実装ではない。君が今後Word VBAで大規模なツールを開発する際の「テンプレート」として機能するはずだ。
業務効率化とは、一度作って終わりではない。現場の運用に耐えうる「壊れない構造」を作ることこそが、我々エンジニアの真の仕事である。次のタスクでは、さらにスタイル(Style)オブジェクトと連動させ、ドキュメントの構造化まで踏み込んでみることを推奨する。
何か疑問があれば聞こう。技術的な壁は、突き破るために存在する。
