「マクロの記録」を卒業する。Word VBAで表をページごとに美しく分割する極限の技法
こんにちは。現場の自動化を司るチーフアーキテクトです。
Wordで膨大なデータを扱っていると、必ずと言っていいほど直面する「壁」があります。それは、「ページを跨いでしまう巨大な表」です。
表が次のページに続いたとき、項目の見出し(ヘッダー)が消えてしまうと、読み手は「この数値、何の項目だっけ……?」と迷子になってしまいます。Wordの標準機能である「見出し行の繰り返し」を使えば解決することもありますが、時には「物理的に表を分割して、それぞれに独立したヘッダーを持たせたい」という、より高度で構造的な要求に突き当たることがあります。
「マクロの記録」でボタンを押すだけの段階から一歩抜け出し、「オブジェクトの構造を操作する」というエンジニアの思考へ。今日は、表のページ区切りを検知し、自動で分割・ヘッダー挿入を行う、実践的なスクリプトを伝授しましょう。
ここをクリアすれば、あなたのWord VBAスキルは「単なる作業の記録」から「真の自動化ツール」へと昇華しますよ。
1. 本質的なロジック:どうやって「ページ」を判定するか
プログラミングにおいて、最も重要なのは「コードを書く前」に、頭の中でアルゴリズムを組み立てることです。今回のミッションは以下の通りです。
1. ドキュメント内のすべての「表(Table)」をスキャンする。
2. 各表の中で、「現在の行」と「次の行」が異なるページに存在するかを判定する。
3. ページが変わった瞬間、その位置で「表を分割(Split)」する。
4. 新しく生成された表の先頭に、元の表の「ヘッダー行」をコピーして流し込む。
ここで重要なテクニックは、`Range.Information(wdActiveEndPageNumber)` というプロパティです。これを使えば、特定の範囲(セルや行)が「ドキュメントの何ページ目に位置しているか」を正確に取得できます。
2. 実装:表分割&ヘッダー自動挿入スクリプト
それでは、魂を込めて書いたコードを見ていきましょう。このコードは、単に動くだけでなく、エラーに強く、メンテナンスしやすい構造を目指しています。
Option Explicit
''' <summary>
''' ページを跨ぐ表を分割し、分割後の表にヘッダー行を自動挿入する
''' </summary>
Sub SplitTablesAtPageBreakAndInsertHeaders()
Dim doc As Document
Dim tbl As Table
Dim i As Long
Dim targetRow As Long
Dim currentPage As Integer
Dim nextPage As Integer
Dim headerRange As Range
Dim splitPoint As Range
' 高速化のための設定:画面更新を停止し、処理速度を劇的に向上させる
Application.ScreenUpdating = False
Set doc = ActiveDocument
' 注意:表を分割すると「表の数」が増えるため、
' 逆順(後ろの表から)に処理するか、インデックスのズレを考慮する必要がある。
' ここでは、ドキュメント内の表を後ろから順番にチェックしていく手法をとる。
For i = doc.Tables.Count To 1 Step -1
Set tbl = doc.Tables(i)
' 表の行を後ろからループ(分割による行番号のズレを防ぐため)
' 2行目以降を対象にする(1行目はヘッダーそのものなので、比較対象として)
For targetRow = tbl.Rows.Count To 2 Step -1
' 現在の行のページ番号を取得
currentPage = tbl.Rows(targetRow).Range.Information(wdActiveEndPageNumber)
' 1つ上の行のページ番号を取得
nextPage = tbl.Rows(targetRow - 1).Range.Information(wdActiveEndPageNumber)
' もし現在の行のページ番号が、前の行と異なる場合(=ページを跨いでいる)
If currentPage <> nextPage Then
' --- 1. ヘッダー行の準備 ---
' 表の1行目をヘッダーとしてコピーするための範囲を設定
Set headerRange = tbl.Rows(1).Range
' --- 2. 分割ポイントの特定 ---
' 分割したい位置(現在の行の開始位置)を取得
Set splitPoint = tbl.Rows(targetRow).Range
splitPoint.Collapse wdCollapseStart
' --- 3. 表の分割実行 ---
' Splitメソッドにより、指定した位置で表が2つに分かれる
' 分割後の「新しい表」が返ってくる
Dim newTbl As Table
Set newTbl = tbl.Split(splitPoint)
' --- 4. ヘッダーの流し込み ---
' 新しい表の1行目に、元のヘッダーをコピーして貼り付け
' ※新しい表の先頭に新しい行を挿入してから貼り付ける
newTbl.Rows.Add BeforeRow:=newTbl.Rows(1)
newTbl.Rows(1).Range.PasteExcelTable False, False, False
' ※補足:PasteExcelTableは書式を維持するのに非常に強力です
End If
Next targetRow
Next i
' 設定を元に戻す
Application.ScreenUpdating = True
MsgBox "表の分割とヘッダーの挿入が完了しました!", vbInformation, "完了"
End Sub
3. プロの視点:ここが「分かれ道」です
コードを書き終えて満足してはいけません。一流のエンジニアは、なぜこの書き方をしたのか、その「理由」を説明できます。
① なぜ「逆順(Step -1)」でループするのか?
これが最も重要なポイントです。
表を分割するということは、ドキュメント内の「表のオブジェクト数」が増えることを意味します。もし前から順番(1, 2, 3…)に処理していくと、表を分割した瞬間に、次に処理すべき表のインデックスがズレてしまい、エラーが発生したり、処理をスキップしてしまったりします。
「構造を破壊(変更)する操作を行うときは、後ろから攻める」。これは、配列やコレクションを操作する際の鉄則です。
② `Split` メソッドの挙動
`tbl.Split(splitPoint)` を実行した瞬間、メモリ上のオブジェクト構造が書き換わります。元の `tbl` は分割された「前の部分」になり、分割された「後ろの部分」は新しい `Table` オブジェクトとして扱われます。この挙動を理解していないと、分割後の操作で迷子になります。
③ パフォーマンスの重み
`Application.ScreenUpdating = False`。
これは単なるおまじないではありません。Wordが「表を分割し、行を挿入し、書式を整える」たびに画面を描画しようとすると、膨大な計算リソースを消費し、処理が極端に重くなります。大規模な文書を扱うなら、この一行は必須の「礼儀」です。
4. 陥りやすいエラーと対策
開発中、以下のような壁にぶつかったら、このチェックリストを確認してください。
- 「実行時エラー ‘5941’: 指定されたオブジェクトが見つかりません」
- 原因:表の分割によって、参照していた `Table` オブジェクトが既に無効になっている可能性があります。前述の「逆順ループ」ができているか確認しましょう。
- ヘッダーの書式が崩れる
- 原因:`Range.Paste` だけでは、セルの結合状態などが正しく引き継がれないことがあります。今回のコードのように `PasteExcelTable` を使うか、あるいは `headerRange.Copy` と `newTbl.Rows(1).Range.Paste` を組み合わせることで、書式を強力に保持できます。
- ページ番号が正しく取得できない
- 原因:表の中に「改ページ」を手動で挿入している場合、判定ロジックが複雑になります。まずは純粋な「データの溢れによる改ページ」でテストを行うのが定石です。
最後に
いかがでしたか?
「表を分割してヘッダーを入れる」という一見単純な作業も、オブジェクトのライフサイクルやインデックスの動きを意識すると、非常に奥深いエンジニアリングの対象になります。
マクロの記録は「答え」を教えてくれますが、VBAのコードは「仕組み」を教えてくれます。仕組みを理解すれば、あなたはもう、Wordに振り回されるユーザーではなく、Wordを支配するエンジニアなのです。
さあ、このコードを自分の環境で試して、その威力を体感してみてください。応援していますよ!
