【入門編】大規模Word文書の分割・結合をVBAで自動化する:メモリ管理とページ番号の連続性を保つ制御術 – Word VBA解析バイブル

スポンサーリンク

こんにちは! Word VBAの世界へようこそ。
マクロの記録ボタンを押して「なんだかよく分からないけれど動いたぞ」というフェーズを抜け出し、自分の手でドキュメントを意のままに操りたいと思っているあなたへ。

今回は、実務で本当によく直面する「大規模文書の分割と結合」というテーマを深掘りします。

数百ページもある分厚い仕様書や報告書をそのまま扱っていませんか? 動作が重くなり、Wordがフリーズする恐怖におびえる日々は、今日で終わりです。ここをクリアすれば、Word VBAのオブジェクトモデルの本質が見えてきますよ。温かく導きますので、ぜひ最後までついてきてくださいね。

なぜ「分割と結合」でエンジニアは頭を悩ませるのか?

Word文書は、Excelのように「行と列」できれいに区切られていません。段落、表、図形、セクション、そして目に見えない制御コードが複雑に絡み合う、いわば「生き物のようなストリーム(流体)」です。

これを単に「一部分を切り取って別ファイルにする」「くっつける」だけでは、以下の大惨事が起きます。
1. ページ番号が「1」に戻ってしまう(または全体で通し番号にならない)
2. 目次(TOC)がリンク切れを起こし、更新できなくなる
3. メモリリークやオブジェクトの解放漏れでWordがクラッシュする

これらを華麗に解決するのが、Word VBAの心臓部である `Range` オブジェクト の正しい理解と、セクション制御 です。

基本のキ:Word VBAのオブジェクトモデルを俯瞰する

まずは、Wordを動かすマトリックス(階層構造)を頭に叩き込みましょう。

Application (Wordそのもの)
┗ Documents (開いている文書たち)
┗ Document (個別のファイル)
┣ Paragraphs / Tables (中身の要素)
┗ Range (文書の「切り取り線」を引ける万能エリア)

「マクロの記録」を使うと、画面上のカーソル(Selection)をあちこち動かすコードが生成されます。しかし、プロのVBAエンジニアは `Selection` を絶対に使いません。なぜなら、画面を描画する分だけ圧倒的に遅くなり、予期せぬエラーの温床になるからです。

代わりに使うのが `Range`(範囲) です。画面を書き換えずに、メモリ上でシュパッと文書を切り貼りする――これが高速化と安定稼働の絶対条件です。

実装編①:大規模文書を「章ごと」に美しく分割する

まずは、1つの巨大なファイルを、見出し(Heading 1など)を基準にして綺麗に分割するコードです。ページ番号の連続性を保つためのヒントもここに隠されています。

Sub SplitDocumentByChapter()
‘ —————————————————-
‘ 巨大文書を指定のセクション単位(または見出し単位)で分割保存する
‘ —————————————————-
Dim docSource As Document
Dim docNew As Document
Dim rngTarget As Range
Dim i As Long
Dim totalSections As Long

Set docSource = ActiveDocument
totalSections = docSource.Sections.Count

‘ セクションが1つだけなら分割の意味がないので離脱
If totalSections <= 1 { MsgBox "分割するセクションがありません。", vbExclamation Exit Sub } ' セクションごとに切り出して別ファイルとして保存 For i = 1 To totalSections ' 対象セクションのRangeを取得 Set rngTarget = docSource.Sections(i).Range ' 新規ドキュメントを作成し、Rangeの内容をコピー Set docNew = Documents.Add docNew.Content.FormattedText = rngTarget.FormattedText ' 保存先のパスを設定(デスクトップ等) Dim savePath As String savePath = docSource.Path & "\Chapter_" & i & ".docx" ' ※同名ファイルが存在する場合は上書き docNew.SaveAs2 FileName:=savePath docNew.Close SaveChanges:=False Set rngTarget = Nothing Next i MsgBox "分割が完了しました!全 " & totalSections & " ファイル", vbInformation End Sub

ここがポイント!

`docNew.Content.FormattedText = rngTarget.FormattedText` という記述に注目してください。単なる文字(Text)ではなく、書式ごと(FormattedText) ゴッソリ移し替えることで、元の表やフォントスタイルが崩れるのを防いでいます。

実装編②:分割した文書を「ページ番号の連続性を保ったまま」結合する

ここが今回の本丸です。バラバラにしたファイルを一つに戻すとき、普通にくっつけると各ファイルの冒頭でページ番号が「1」にリセットされてしまいます。

これを防ぐには、文書を結合する際に「セクション区切り(前のセクションと継続)」を明示的に挟み込む必要があります。

Sub MergeDocumentsWithPageNumbering()
‘ —————————————————-
‘ 分割された文書を順番に結合し、ページ番号を連続させる
‘ —————————————————-
Dim docMaster As Document
Dim targetFiles As Variant
Dim i As Long
Dim rngInsert As Range

‘ 結合したいファイルのリスト(実際にはファイルダイアログ等で動的取得すると便利です)
‘ ここでは例として Chapter_1.docx から Chapter_3.docx までを想定
targetFiles = Array(“Chapter_1.docx”, “Chapter_2.docx”, “Chapter_3.docx”)

‘ 新規マスター文書を作成
Set docMaster = Documents.Add

For i = LBound(targetFiles) To UBound(targetFiles)
Dim filePath As String
filePath = docMaster.Path & “\” & targetFiles(i)

‘ 最初以外のファイルを追加する場合は、セクション区切りを入れてページ番号を継続させる
If i > 0 {
‘ 文書の末尾にセクション区切り(次のページから、または連続)を追加
docMaster.Content.InsertParagraphAfter
docMaster.Range.End.InsertBreak Type:=wdSectionBreakContinuous
}

‘ 末尾に外部ファイルを挿入
Set rngInsert = docMaster.Content
rngInsert.Collapse Direction:=wdCollapseEnd
rngInsert.InsertFile FileName:=filePath

Next i

‘ 結合後のページ番号フィールドを強制更新(重要!)
docMaster.Fields.Update

MsgBox “すべての文書がページ番号の連続性を保ったまま結合されました!”, vbInformation
End Sub

陥りやすいエラーと回避策

  • 「ファイルが見つからない(エラー 5152)」:結合するファイル群が、マスター文書と同じフォルダ(`docMaster.Path`)に存在するか確認してください。絶対パスで指定するのが安全です。
  • ページ番号が繋がらない原因:Wordのヘッダー・フッターには「前のセクションと同じ」という呪縛(`LinkToPrevious` プロパティ)があります。もしページ番号がリセットされてしまう場合は、結合後のセクションに対して `rngInsert.Sections(1).Headers(wdHeaderFooterPrimary).LinkToPrevious = True` を明示的に設定してあげる必要があります。

プロの知見:メモリ管理とパフォーマンスの極意

最後に、大規模文書を扱う上で絶対に知っておくべき「メモリ管理の作法」を伝授します。

1. 画面描画の停止(ScreenUpdatingの無効化)
処理の最初に `Application.ScreenUpdating = False` を入れ、最後に `True` に戻します。これだけで実行速度が数倍〜十数倍に跳ね上がります。
2. オブジェクトの即座の解放(`Set … = Nothing`)
大きな `Range` や `Document` オブジェクトを変数に代入し続けると、VBAのガベージコレクションが追いつかず、メモリリーク(メモリ食い潰し)を起こしてWordが突然落ちます。使い終わったオブジェクトは、ループの都度 `Set rngTarget = Nothing` で綺麗に掃除する癖をつけましょう。

まとめ

いかがでしたか?
「画面をカチカチ動かすマクロ」から、「メモリ上で `Range` を自在に操るVBA」へのステップアップ。ここをクリアすれば、どれほど分厚いマニュアルや仕様書が相手でも、あなたのVBAは決して音を上げません。

ここをクリアしたあなたなら、もうWord VBAの基本はバッチリです。ぜひ実際の業務データで試してみてくださいね。次回の応用編もお楽しみに!

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