【実務・中級編】【中級者向け】Word文書内の「強調箇所」を抽出して別ファイルにリスト化する自動化スクリプト – Word VBA解析バイブル

スポンサーリンク

【Word VBA極限活用】「太字・赤字」の強調箇所を自動抽出せよ!散逸した重要情報を1秒でリスト化する堅牢なVBAアーキテクチャ

開発現場のプロジェクトリーダーである私に、よくこんな相談が持ち込まれる。
「膨大な仕様書や議事録から、太字や赤字になっている『重要ポイント』だけを抜き出してサマリーを作りたい。手作業でコピペしていると半日かかるし、見落としも発生する。なんとかならないか?」

Word文書の書式設定は、人間の目には美しく映るが、VBAのオブジェクトモデルを理解していない者が書いたコードにとっては「地雷原」そのものだ。段落全体をスキャンするだけなら初級者でも書けるが、「特定の文字装飾(太字・赤字)が施された部分」を正確に射抜き、別ファイルに美しく構造化して出力するとなると話は別だ。

今回は、実務の現場で「絶対に破綻しない」堅牢性を備え、かつパフォーマンスを極限まで高めたWord VBAのプロダクションコードを伝授する。

1. なぜ「力技の検索」は実務で破綻するのか?

多くのVBAプログラマ(あるいはAIが出力する安易なコード)は、次のようなアプローチをとる。

1. 文書の先頭から `Paragraphs` コレクションを `For Each` で総なめにする。
2. 段落の `Range.Bold` や `Range.Font.Color` をチェックする。

これでは実務で必ずバグる。 なぜなら、Wordの段落プロパティ(`Paragraph.Range`)は、「段落全体」の書式を返す仕様になっているからだ。「段落の一部だけが太字になっている」場合、`Paragraph.Range.Bold` は `vbUndefined`(中途半端な状態を示す `-999999`)を返し、部分的な装飾を完全にスルーしてしまうのだ。

さらに、`Selection` オブジェクトを多用したコードは、画面のチラつき(スクロール)を引き起こし、実行速度を劇的に低下させる。実務で使うツールなら、画面描画を完全にロックし、`Range` オブジェクトだけでメモリ上で高速処理するのが鉄則だ。

2. 堅牢な抽出エンジンの設計思想

今回のアーキテクチャの核心は以下の通りである。

  • Findオブジェクトの駆使: Wordの真骨頂である `Find` 機能を用い、「太字」または「赤字」の属性を持つテキストピースをピンポイントでヒットさせる。
  • 重複とノイズの排除: ヘッダー・フッターや表の枠内など、不要な領域を除外し、本文エリアの純粋な「強調箇所」だけを狩り出す。
  • 新規ドキュメントへのクリーン出力: 抽出した結果は、散らからないよう自動生成したクリーンな新規Word文書に美しい箇条書きリストとして流し込む。

3. 【コピペ即稼働】プロダクション・VBAコード

以下のコードをWordのVBAエディタ(標準モジュール)に貼り付けて実行してほしい。実務での耐性を考慮し、エラーハンドリングと画面描画の抑止(パフォーマンス最適化)を組み込んである。

Option Explicit

‘ ==============================================================================
‘ 処理名: アクティブ文書から強調箇所(太字・赤字)を抽出し、別ファイルにリスト化する
‘ アーキテクチャ特性: 画面描画抑制による高速化、Findオブジェクトによる部分一致対応
‘ ==============================================================================
Sub ExtractEmphasizedTextToNewDocument()
Dim srcDoc As Document
Dim tgtDoc As Document
Dim rngTarget As Range
Dim foundCount As Long

‘ 0. エラーハンドリングとパフォーマンス最適化の準備
On Error GoTo ErrorHandler
Application.ScreenUpdating = False
Application.DisplayAlerts = wdAlertsNone

Set srcDoc = ActiveDocument
foundCount = 0

‘ 1. 出力用の新規ドキュメントを作成
Set tgtDoc = Documents.Add

‘ ヘッダーの設定
With tgtDoc.Content
.Text = “【重要強調箇所抽出レポート】” & vbCrLf & _
“生成日時: ” & Format(Now, “yyyy/mm/dd HH:nn:ss”) & vbCrLf & _
“元ファイル: ” & srcDoc.Name & vbCrLf & _
String(40, “-“) & vbCrLf & vbCrLf
.Collapse wdCollapseEnd
End With

‘ 2. 検索範囲を元文書の本文に限定
Set rngTarget = srcDoc.Content

‘ Findオブジェクトの設定(初期化)
With rngTarget.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = “”
.MatchWildcards = False
.MatchCase = False

‘ ループ処理:文書全体から「太字」または「赤字」を検索
Do While .Execute
‘ 検索ヒットしたテキストが空白や改行のみの場合はスキップ
If Len(Trim(rngTarget.Text)) > 0 Then

‘ 条件判定:太字である、または文字色が赤(wdColorRed / RGB(255,0,0)等)である場合
If rngTarget.Font.Bold = True Or rngTarget.Font.Color = wdColorRed Or rngTarget.Font.ColorIndex = wdRed Then

‘ ターゲット文書に抽出テキストを追加(箇条書き風)
tgtDoc.Content.InsertAfter “・ ” & CleanText(rngTarget.Text) & ” (” & GetParentParagraphInfo(rngTarget) & “)” & vbCrLf
foundCount = foundCount + 1

End If

End If

‘ 検索位置をヒットしたテキストの末尾に移動し、無限ループを防止
rngTarget.Collapse wdCollapseEnd
Loop
End With

‘ 3. 結果の総括を追加
tgtDoc.Content.InsertAfter vbCrLf & String(40, “-“) & vbCrLf & _
“抽出完了: 合計 ” & foundCount & ” 件の強調箇所を検出しました。”

‘ 4. 完了メッセージ
Application.ScreenUpdating = True
Application.DisplayAlerts = wdAlertsAll

MsgBox “抽出処理が正常に完了しました。” & vbCrLf & _
“検出件数: ” & foundCount & ” 件”, vbInformation, “処理成功”
Exit Sub

ErrorHandler:
‘ 異常系処理
Application.ScreenUpdating = True
Application.DisplayAlerts = wdAlertsAll
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error: ” & Err.Description, vbCritical, “システムエラー”
End Sub

‘ ==============================================================================
‘ 補助関数: テキスト内の改行やタブをスペースに置換し、レイアウト崩れを防ぐ
‘ ==============================================================================
Private Function CleanText(ByVal txt As String) As String
txt = Replace(txt, vbCr, ” “)
txt = Replace(txt, vbLf, ” “)
txt = Replace(txt, vbTab, ” “)
CleanText = Trim(txt)
End Function

‘ ==============================================================================
‘ 補助関数: 該当テキストがどの段落(何番目か)に属しているかを返す
‘ ==============================================================================
Private Function GetParentParagraphInfo(ByVal rng As Range) As String
On Error Resume Next
Dim paraNum As Long
paraNum = rng.Paragraphs(1).Range.Information(wdActiveEndAdjustedPageNumber)
GetParentParagraphInfo = “P.” & paraNum
On Error GoTo 0
End Function

4. コードのアーキテクチャ的解説(プロがこだわるポイント)

このコードが「ただ動くだけのスクリプト」と決定的に違うのは、以下の3点に集約される。

① `Application.ScreenUpdating = False` による爆速化

Word VBAで最もボトルネックになるのは「画面の再描画」だ。数万字ある文書でこれをオンにしたまま検索・挿入を繰り返すと、画面がバグったようにチラつき、処理が何倍も遅くなる。プロのコードは、処理の最初に画面を凍結し、最後に一気に解放する。

② 無限ループを防ぐ `rngTarget.Collapse wdCollapseEnd`

`Find.Execute` を使う際、検索範囲の縮小と移動(Collapse)を怠ると、同じ場所を無限にループし続ける致命的なバグ(ハングアップ)を引き起こす。ヒットした末尾にレンジを縮小し、「次を検索する」という王道のイディオムを正確に実装している。

③ 実務に配慮したメタ情報の付与

単に文字列を抜き出すだけでなく、補助関数 `GetParentParagraphInfo` を通して「何ページのどの段落から抽出されたか」のコンテキスト(文脈)を添えている。これにより、出力されたリストを見た人間が、元の文書のどこに戻って確認すればいいかが一目瞭然となる。

5. さらなる高みへ:Excel連携への拡張

今回は「新規Word文書」に出力したが、実務要件によっては「Excelの一覧表(データベース形式)に流し込みたい」というケースもあるはずだ。その場合は、VBAからExcelのCOMオブジェクト(`CreateObject(“Excel.Application”)`)を叩き、セルにマッピングしていくことで容易に拡張できる。

業務自動化において、手作業の代替は「コスト削減」ではなく「ミスという名のリスクの排除」である。このスクリプトをあなたのローカル環境、あるいはチームの共有テンプレートに組み込み、日々のドキュメント地獄から解放されることを願う。

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