こんにちは!Word VBAの世界へようこそ。
マクロの記録ボタンを押して出てきたコードを眺めるだけの段階は、もう卒業しましょう。ここをクリアすれば、Word VBAの本質をグッと掴み、どんな複雑な文書もあなたの手足のように自在に操れるようになりますよ。
今回は、Word文書の骨組みである「アウトラインレベル」をプログラムで完全にハッキングし、その階層構造を美しくツリー形式でイミディエイトウィンドウに出力するテクニックを伝授します。
文書の構造をコードで正確に把握できるようになると、自動目次の生成、特定階層以下のデータ抽出、果ては高度なドキュメント自動生成まで、業務自動化の幅が圧倒的に広がります。さあ、一緒に扉を開けましょう!
—
1. なぜ「アウトラインレベル」の解析が重要なのか?
私たちが普段作成するWord文書には、「見出し1」「見出し2」といったスタイルが設定されていますよね。Wordの内部では、これらは単に「文字が大きい・太い」だけではなく、「アウトラインレベル(Outline Level)」という論理的な階層構造を持っています。
- レベル 1:大見出し(章)
- レベル 2:中見出し(節)
- レベル 3:小見出し(項)
- レベル 9:本文(通常の段落)
人間であれば、文書を目で見れば「あ、ここが大きな章なんだな」と分かりますが、VBAにとっても同じです。このアウトラインレベルを上手に読み取ることで、「コンピュータに文書の構造を理解させる」ことができるようになります。
—
2. 実装コード:文書の構造をツリー化する
それでは早速、実際のコードを見てみましょう。
以下のコードをWordのVBAエディタ(Alt + F11)の標準モジュールに貼り付けて実行してみてください。
Option Explicit
‘ ==============================================================================
‘ 処理名 : 文書のアウトライン構造を解析し、イミディエイトウィンドウにツリー出力する
‘ 対象者 : マクロの記録から脱却し、Wordの文書構造をプログラムで制御したい方へ
‘ ==============================================================================
Public Sub OutputDocumentTree()
Dim para As Paragraph
Dim targetLevel As Long
Dim indentStr As String
Dim displaytext As String
‘ 文書全体の段落コレクションを高速かつ安全にループする
Dim doc As Document
Set doc = ActiveDocument
Debug.Print “=== 文書構造ツリー解析開始: ” & doc.Name & ” ===”
For Each para in doc.Paragraphs
‘ 1. 段落のアウトラインレベルを取得
‘ ※Wordの OutlineLevel は 1~9(本文は wdOutlineLevelBody = 10)を返す
targetLevel = para.OutlineLevel
‘ 2. 本文(レベル10)はノイズになるため、見出しレベル(1~9)のみを抽出対象とする
If targetLevel >= 1 And targetLevel <= 9 then
' 3. 階層に応じたインデント(ツリーの枝葉の表現)を動的に生成
indentStr = Space((targetLevel - 1) 4) ' 1レベルにつき半角スペース4つ
' 4. 段落のテキストを取得(末尾の改行コードや特殊文字をトリムして綺麗にする)
displaytext = CleanText(para.Range.Text)
' 5. イミディエイトウィンドウに出力
' 出力イメージ: [Lv.1] はじめに
Debug.Print "[Lv." & targetLevel & "] " & indentStr & "└─ " & displaytext
End If
Next para
Debug.Print "=== 解析完了 ==="
End Sub
' ==============================================================================
' 補助関数 : 段落テキストからWord特有の制御文字(改行やタブ)を除去する
' ==============================================================================
Private Function CleanText(ByVal rawText As String) As String
' Wordの段落末尾には必ず「vbCr(キャリッジリターン)」が含まれているためこれを削除
rawText = Replace(rawText, vbCr, "")
rawText = Replace(rawText, vbLf, "")
rawText = Replace(rawText, vbTab, " ")
' 長すぎる見出しはログが見づらくなるため、必要に応じて切り詰める(今回は最大40文字)
If Len(rawText) > 40 then
rawText = Left(rawText, 40) & “…”
End If
CleanText = rawText
End Function
—
3. コードのキモを徹底解説!ここがエンジニアの知見
初心者から一歩抜け出すために、このコードに込めた設計のポイントをいくつか解説します。
① `Paragraph.OutlineLevel` の罠を見抜け
Word VBAで段落を扱う際、`para.Style`(スタイルの名前)を見に行ってしまいがちです。しかし、「見出し1」という名前はユーザーが自由に変更できてしまいますし、英語環境と日本語環境で名前が異なり(”Heading 1″ と “見出し 1″)、バグの温床になります。
「スタイル名に頼らず、プロパティ(OutlineLevel)を見る」。これが実務で通用する堅牢なコードを書く極意です。
② 本文(レベル10)のフィルタリング
Wordの `OutlineLevel` プロパティは、見出し以外の「本文」に対しては `wdOutlineLevelBody`(数値としては `10`)を返します。
文書内のすべての段落をそのまま出力すると、長文のときはイミディエイトウィンドウがゴミデータで埋め尽くされてしまいます。`If targetLevel >= 1 And targetLevel <= 9` という条件を挟むことで、見出し構造だけをピュアに抽出しているのです。
③ 文字列のクリーニング (`CleanText`)
Wordの `Paragraph.Range.Text` をそのまま取得すると、文字列の末尾に必ず `vbCr`(段落記号)がくっついてきます。これを放置すると、イミディエイトウィンドウで意図しない改行が発生してしまいます。細部へのこだわりですが、こういう小さなケアがプログラムの品質を大きく引き上げます。
—
4. 陥りやすいエラーと対策
このコードを動かす上で、初心者がハマりがちなポイントを先回りして解説しておきます。
- エラー:「オブジェクト変数または With ブロック変数が設定されていません。」(実行時エラー 91)
- 原因:開いているアクティブな文書がない状態でコードを実行すると発生します。
- 対策:必ず何かしらのWord文書を開いた状態でマクロを実行するようにしてください。
- 「何も出力されないんだけど?」
- 原因:対象の文書に「見出し1」〜「見出し9」のアウトラインレベルを持つ段落が一つも設定されていない場合に起こります。
- 対策:文書の適当な行を選択し、ホームタブから「見出し 1」スタイルをいくつか適用してから再度マクロを実行してみてください。
—
おわりに:ここをクリアすれば、Word VBAの基本はバッチリです!
お疲れ様でした!今回は「アウトラインレベルの解析」という、やや渋いけれど非常に強力なテーマを扱いました。
文書の「構造」をプログラムが理解できるようになると、例えば以下のような高度な自動化へステップアップできます。
- 特定の「見出し2」の下にある段落だけを別のファイルに一括抽出する
- 階層の抜け漏れ(「見出し1」の次にいきなり「見出し3」が来ているなど)を自動チェックするツールを作る
Word VBAは、ただの「お絵かきマクロ(操作の記録)」ではありません。文書という構造体をロジカルに料理する、最高にエキサイティングなプログラミング言語です。
この知見をあなたの武器にして、日々のドキュメント業務を鮮やかに自動化してくださいね。それでは、次のステップでお会いしましょう!
