【実務・中級編】Word VBAにおける『Range.FormattedText』による書式付きテキストの高速コピー – Word VBA解析バイブル

スポンサーリンク

Word VBAを掌握する極限の知見:`Range.FormattedText`による書式付きテキスト高速転送術

開発現場でこんなコードを見たことはないだろうか。

‘ 【アンチパターン】絶対にやってはいけないクリップボード依存の処理
Selection.Copy
Selection.Paste

もし、あなたが数百ページに及ぶドキュメントの生成や、大量の定型句・条文を組み立てるエンタープライズ向けのWordマクロを開発しているなら、この「選択してコピー&ペースト」というアプローチは今すぐ捨てていただきたい。

遅い。不安定。そして何より、画面のチラつき(スクリーニング)が激しい。
Word VBAにおけるパフォーマンス低下の最大のガンは、「不要なUIオブジェクト(Selection)への依存」「Windowsクリップボードの経由」にある。

今回は、Wordのオブジェクトモデルの深層を知る者だけが使う、`Range.FormattedText`プロパティを用いた極限の高速転送テクニックを伝授する。

なぜ `Selection.Copy / Paste` は悪なのか?

Word VBA初心者が最初に覚えるのが `Selection` オブジェクトを使った操作だ。しかし、`Selection` は「現在ユーザーが見ている画面上のカーソル位置」を模倣するものであり、UIの描画処理を伴うため圧倒的に重い。

さらに、`Copy` メソッドや `Paste` メソッドを実行すると、OSのクリップボード領域にデータが書き込まれる。

  • 他のアプリケーションとの予期せぬ干渉(クリップボードエラー)
  • クリップボードのクリア処理による処理落ちは、実務のバグ報告の定番だ。

救世主:`Range` オブジェクトと `FormattedText`

これに対し、`Range` オブジェクトは画面の描画(UI)とは切り離された、メモリ上の文書領域を指す。
`FormattedText` プロパティは、フォント、サイズ、段落書式、さらには表やインライン図形まで含めた「リッチテキストの塊」を、クリップボードを一切汚さずに、純粋なメモリ間(VBAの変数およびドキュメント間)でダイレクトに転送する。

速度差は歴然だ。数千回のループ処理を行った場合、`FormattedText` を使ったロジックは、クリップボード経由のものと比較して 最大で10倍以上のパフォーマンス を叩き出す。

プロダクションコード:堅牢な「条文・定型句アセンブラ」

実務でそのまま使える、堅牢なモジュール設計のコードを提示する。
このコードは、マスター文書(またはテンプレート)の特定の「セクションやブックマーク」から書式付きのテキストをごっそり取得し、別ドキュメントの指定位置へミリ秒単位の速度で流し込むものだ。

Option Explicit

”’

”’ クリップボードを使用せず、FormattedTextを用いて書式を維持したままテキストを高速転送する
”’

Public Sub ExecuteHighSpeedTransfer()
Dim wsSource As Document
Dim wsTarget As Document
Dim rngSource As Range
Dim rngTarget As Range

‘ エラーハンドリングの標準装備
On Error GoTo ErrorHandler

‘ 画面描画と言い換えを停止し、実行速度を極限まで引き上げる
Application.ScreenUpdating = False
Application.DisplayAlerts = wdAlertsNone

‘ 【前提】転送元と転送先のドキュメントがすでに開いていると仮定
‘ 実務では必要に応じて Workbooks.Open 相当の処理を記述
Set wsSource = ActiveDocument ‘ サンプルとしてアクティブドキュメントを元にする
Set wsTarget = Documents.Add ‘ 新規ドキュメントを転送先とする

‘ 1. コピー元のレンジを設定(例:先頭の段落)
Set rngSource = wsSource.Paragraphs(1).Range

‘ 2. 転送先の挿入位置を決定(例:ターゲット文書の末尾)
Set rngTarget = wsTarget.Content
rngTarget.Collapse wdCollapseEnd

‘ =====================================================================
‘ 【核心】FormattedTextによるダイレクト転送
‘ =====================================================================
‘ クリップボードを経由せず、書式情報(Font, ParagraphFormat等)ごと一瞬でコピー
rngTarget.FormattedText = rngSource.FormattedText

‘ 処理成功のログ出力など
MsgBox “書式付きテキストの転送が完了しました。”, vbInformation, “高速転送エンジン”

CleanUp:
‘ 描画の復元(絶対に忘れてはならない)
Application.ScreenUpdating = True
Application.DisplayAlerts = wdAlertsAll
Exit Sub

ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
Resume CleanUp
End Sub

現場で絶対にハマる「3つの罠」と設計上の注意点

この `FormattedText` は強力だが、オブジェクトモデルの挙動を理解していないと、実務で不可解なバグを生む。チーフアーキテクトとして、現場で陥りがちな罠と回避策を共有しておこう。

1. ターゲットの「レンジの伸び縮み(拡張)」に注意せよ

`rngTarget.FormattedText = rngSource.FormattedText` を実行すると、`rngTarget` 自体が「新しく挿入されたテキストの範囲」に自動的に拡張される。
もし連続して複数のブロックを転送したい場合は、代入の都度、レンジの末尾に縮小(Collapse)させる必要がある。

‘ 連続して転送する場合の正しいイディオム
rngTarget.FormattedText = rngSource1.FormattedText
rngTarget.Collapse wdCollapseEnd ‘ 常に末尾にカーソルを移動させる感覚

rngTarget.FormattedText = rngSource2.FormattedText
rngTarget.Collapse wdCollapseEnd

2. `ScreenUpdating = False` は例外処理とセットで実装せよ

高速化のために `Application.ScreenUpdating = False` を使うのは鉄則だが、コードの途中でエラー(ゼロ除算やオブジェクト不一致など)が発生して処理が中断すると、Wordの画面がフリーズしたような状態(描画停止のまま)でユーザーに放置されるという最悪のUXを招く。
必ず上記のサンプルコードのように、`On Error GoTo` を用いて、いかなる場合でも `ScreenUpdating = True` が実行されるクリーンアップ動線を確保すること。

3. データベースや外部ファイル連携時の文字コード・段落記号の扱い

データベース(SQL ServerやSQLiteなど)から取得したプレーンテキストをWordに流し込む際、改行コード(`vbCrLf`など)が含まれている場合がある。
単に `Range.Text` に代入すると、Wordの段落区切り(¶)が崩れたり、フォント書式がデフォルトにリセットされる。
外部データと連携する場合は、「ベースとなる定型スタイルが適用されたRange」に対して `FormattedText` ではなく通常のテキスト代入を行い、その後スタイルを適用するか、あらかじめテンプレート側に用意したプレースホルダー(ブックマーク)の `Range.FormattedText` ごと置き換える設計にすべきだ。

結論:プロのVBAコードは「美しく、速い」

業務自動化ツールを作るエンジニアの価値は、「ただ動くものを作る」ことではなく、「大規模データや長期間の運用でも耐えうる、堅牢で高速なアーキテクチャを構築する」ことにある。

`Selection` を廃し、`Range` と `FormattedText` を使いこなす。
たったこれだけの設計思想の転換が、あなたの書くWord VBAを「おもちゃのマクロ」から「エンタープライズグレードの自動化ソリューション」へと昇華させる。

次の開発案件から、ぜひこの知見を組み込んでほしい。圧倒的なパフォーマンスの差に驚くはずだ。

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