【実務・中級編】【中級者向け】段落の「段落前後の間隔」を、セクションごとに自動調整するツール – Word VBA解析バイブル

スポンサーリンク

プロの流儀:Wordの「段落間隔」をセクション単位で支配する

「100ページ超の仕様書、セクションごとに見出しの前後スペースを微調整してくれ」
もし君が、この依頼に対してマウスを握り、1つずつ段落プロパティを開こうとしているなら、今すぐその手を止めろ。それはエンジニアの仕事ではなく、苦行だ。

Word VBAにおいて、段落(Paragraph)の操作は最も基本でありながら、最も「設計の甘さ」が出る領域だ。特に「段落前後の間隔(SpaceBefore/After)」の制御は、文書の可読性を左右する決定的なファクターだ。

今日は、単なるループ処理ではない。セクション(Section)という構造を理解し、各セクションの役割に応じてレイアウトを動的に再定義する、堅牢な自動化ツールの設計思想を伝授する。

1. なぜ「全段落ループ」は三流のコードなのか

初心者はよく `ActiveDocument.Paragraphs` を `For Each` で回そうとする。だが、数千段落ある文書でそれをやれば、処理速度は目に見えて落ち、さらに「特定の章だけは例外」という要件に対応できず、スパゲッティコードが完成する。

優れたアーキテクトの視点はこうだ:
1. セクション構造の把握: 文書を「表紙」「目次」「本文」「付録」というセクション単位で捉える。
2. スタイルへの委譲: 基本はスタイル(Style)で制御し、例外的な微調整のみを直接フォーマット(Direct Formatting)で行う。
3. Rangeオブジェクトの局所化: `Selection` は絶対に使わない。`Range` オブジェクトを使い、メモリ内で処理を完結させる。

2. プロダクション・グレードの実装例

このコードは、セクションの「インデックス」や「ページ設定」をトリガーに、段落間隔を動的に切り替えるものだ。保守性を高めるため、定数管理とロジックを分離している。

Option Explicit

‘ — 定数定義:マジックナンバーを排除し、ここを修正するだけで仕様変更に対応する —
Private Const SPACING_STANDARD_BEFORE As Single = 6 ‘ 標準の段落前:6pt
Private Const SPACING_STANDARD_AFTER As Single = 6 ‘ 標準の段落後:6pt
Private Const SPACING_HEADING_BEFORE As Single = 18 ‘ 見出しの段落前:18pt
Private Const SPACING_APPENDIX_BEFORE As Single = 3 ‘ 付録セクションの段落前:3pt

”’

”’ セクションごとの役割に応じた段落間隔の自動最適化
”’

Public Sub OptimizeSectionLayouts()
Dim doc As Document
Set doc = ActiveDocument

Dim sec As Section
Dim para As Paragraph
Dim targetRange As Range

‘ 描画停止による高速化と画面のチラつき防止
On Error GoTo ErrorHandler
Application.ScreenUpdating = False

‘ 文書全体のセクションを走査
For Each sec In doc.Sections
Set targetRange = sec.Range

‘ セクションの性質を判定(例:セクション番号やページ設定で分岐)
‘ 実務ではセクションの開始ページやヘッダー内容で判定することもある
Select Case sec.Index
Case 1 ‘ 第1セクションは通常「表紙」や「概要」
ApplyParagraphSpacing targetRange, 0, 12

Case doc.Sections.Count ‘ 最終セクションは「付録」や「索引」
ApplyParagraphSpacing targetRange, SPACING_APPENDIX_BEFORE, 0

Case Else ‘ それ以外のメインコンテンツ
‘ スタイル(見出し1など)を考慮した高度な適用
ApplyAdvancedSpacing targetRange
End Select
Next sec

MsgBox “レイアウト最適化が完了しました。”, vbInformation

CleanUp:
Application.ScreenUpdating = True
Exit Sub

ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical
Resume CleanUp
End Sub

”’

”’ 特定の範囲(Range)内の段落に対し、スタイルを判別して間隔を適用する
”’

Private Sub ApplyAdvancedSpacing(ByRef rng As Range)
Dim p As Paragraph
For Each p In rng.Paragraphs
‘ スタイル名に基づいた動的な制御
‘ スタイル名が「見出し」を含むか、アウトラインレベルで判定するのがプロのやり方だ
If p.OutlineLevel <= wdOutlineLevel3 Then ' 見出し1〜3に対する処理 p.Format.SpaceBefore = SPACING_HEADING_BEFORE p.Format.SpaceAfter = 6 p.Format.KeepWithNext = True ' 次の段落と分離させない(重要) Else ' 標準テキストに対する処理 p.Format.SpaceBefore = SPACING_STANDARD_BEFORE p.Format.SpaceAfter = SPACING_STANDARD_AFTER End If Next p End Sub '''

”’ 範囲内の全段落に一括で間隔を適用(高速処理用)
”’

Private Sub ApplyParagraphSpacing(ByRef rng As Range, before As Single, after As Single)
With rng.ParagraphFormat
.SpaceBefore = before
.SpaceAfter = after
End With
End Sub

3. チーフアーキテクトによる解説:ここが「差」になる

① `KeepWithNext`(次の段落と分離しない)の制御

段落間隔を広げた際、最悪なのは「見出しがページの最後の一行になり、本文が次ページに送られる」ことだ。コード内で `p.Format.KeepWithNext = True` を指定しているのは、自動化によるレイアウト崩れを防ぐためのプロの配慮だ。

② スタイル名ではなく `OutlineLevel` を使う理由

`p.Style = “見出し 1″` という書き方は危険だ。Wordの言語設定(日本語・英語)によってスタイル名が変わるからだ。`OutlineLevel` を参照すれば、言語に依存せず「見出し」を正確にキャッチできる。これが「堅牢な設計」の正体だ。

③ セクション区切りの罠

Wordの `Section` オブジェクトの `Range` には、セクション区切りそのものが含まれる。これを不用意に書き換えると、次セクションのページ設定(横向きなど)が前セクションに継承されてしまう事故が起きる。
本スクリプトでは `ParagraphFormat` を操作しているが、もし文字装飾まで踏み込むなら、`rng.End – 1` でセクションマークを除外する処理が必要になることを覚えておいてほしい。

4. データベース・外部ファイル連携への拡張

実務では、これらの設定値(18pt、6ptなど)をコード内にハードコードせず、JSONやExcelの定義ファイルから読み込むのが一般的だ。

  • Excel連携: 設定値を管理するExcelを「マスター」とし、VBAから `Workbooks.Open` で値を引き出す。
  • 保守性の向上: デザイナーが「やっぱり見出しの前は20ptにして」と言い出したとき、君はコードを書き換える必要はない。設定ファイルの数字を書き換えて、ツールを実行する。それだけで数千ページの文書が再定義される。

結言

Word VBAは、単なる「記録マクロの延長」ではない。オブジェクトの階層構造と、Wordというアプリケーションの「振る舞いの癖」を理解した者が書くコードは、芸術的なまでに正確で速い。

君が作るツールが、単に動くだけでなく、誰がいつ見てもその意図が伝わり、かつメンテナンスしやすい「プロダクト」であることを期待する。

「自動化とは、人間の時間を奪う作業を、機械に誇りを持って譲り渡す儀式である」

このコードをベースに、君の現場に最適な最強のレイアウトエンジンを構築してくれ。

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