【実務・中級編】【中級者向け】検索対象の文字列を「配列」に格納して、複数キーワードを一括置換する – Word VBA解析バイブル

スポンサーリンク

【Word VBA】複数キーワードの泥臭い置換に終止符を。二次元配列で実現する「一括置換エンジン」の設計思想

Word VBAにおける `.Find` と `.Replacement` の組み合わせは、文書自動化の要である。しかし、実務でこの機能を使おうとした瞬間、多くの開発者が壁にぶつかる。

「置換したいキーワードが数十個、あるいは数百個ある。まさか `Find.Execute` のコードを何十行もコピペし続けるのか?」

もし君が、散らばった文字列置換コードを延々と並べていたり、文書オブジェクト(Range)をループのたびに無駄に生成・破棄しているなら、今すぐその手を止めてほしい。それはコードの保守性を殺し、実行速度を極限まで低下させる典型的なアンチパターンだ。

今回は、「検索・置換のリストを二次元配列でメモリ上に展開し、Wordのエンジンを極限まで効率よく叩くプロダクションコード」を伝授する。実務の荒波に耐えうる、堅牢で美しいアーキテクチャを一緒に見ていこう。

—

1. なぜ「個別の置換コードの羅列」は悪なのか?

実務の現場で最も恐ろしいのは、要件変更(「この言葉は別の言葉に一斉に変更してほしい」という指示)が突然やってくることだ。

もし `Find` 処理をベタ書きしていたらどうなるか?

  • 修正箇所がコード全体に散らばり、漏れが発生する。
  • 配列を使わず、セルやファイルから動的にキーワードを読み込む際、I/O(入出力)のコストで実行速度が激遅になる。
  • 検索のヒット条件(大文字小文字の区別、ワイルドカードの有無など)の変更時に、すべてのロジックを修正し直すハメになる。

プロフェッショナルな自動化エンジニアなら、「データ(置換リスト)」と「ロジック(置換エンジン)」を完全に分離させるべきだ。メモリ上で完結する配列を駆使し、WordのCOMコンポーネントへのアクセス回数を最小限に抑える設計こそが、正解となる。

—

2. 堅牢な一括置換エンジンの全体像

今回構築するアーキテクチャのポイントは以下の3点だ。

1. 二次元配列によるマスターデータの保持:`(N行, 0列: 検索ワード, 1列: 置換ワード)` の形式でメモリ上にリストを持つ。
2. 高速化(ScreenUpdating等の制御):画面描画やバックグラウンド処理の無駄を削ぎ落とし、パフォーマンスを最大化する。
3. エラーハンドリングとステータс通知:万が一のクラッシュを防ぎ、処理件数をログに出力する。

—

3. 【コピペ即 PULL】プロダクションコード

以下のコードをそのまま標準モジュールに貼り付けて実行してほしい。実務のドキュメント整形ツールとして、そのまま組み込めるクオリティに仕上げている。

Option Explicit

‘ =================================================================================
‘ 担当者名: チーフアーキテクト
‘ 概要 : 二次元配列を用いた複数キーワードの一括置換エンジン
‘ 備考 : WordのFindオブジェクトの冗長なインスタンス生成を避け、高速かつ確実に置換を行う
‘ =================================================================================
Sub ExecuteBatchReplace()
Dim startTime As Double
startTime = Timer

‘ 1. 画面描画と自動計算を停止(パフォーマンス劇的向上のお約束)
With Application
.ScreenUpdating = False
.DisplayAlerts = wdAlertsNone
.Calculation = wdCalculationManual
End5 With

On Error GoTo ErrorHandler

‘ 2. 置換マスターデータを二次元配列に格納 (検索ワード, 置換ワード)
‘ ※実務では、ここをExcelシートや外部CSVからの読み込みに拡張することも容易です
Dim replaceList() As String
replaceList = GetReplacementMaster()

Dim totalReplaces As Long
totalReplaces = UBound(replaceList, 1) – LBound(replaceList, 1) + 1

‘ 3. 検索・置換オブジェクトの取得と初期化
Dim tgtRange As Range
Set tgtRange = ActiveDocument.Content ‘ 文書全体をターゲットにする

Dim wdFind As Find
Set wdFind = tgtRange.Find

Call InitializeFindObject(wdFind)

‘ 4. 配列をループして一括置換を実行
Dim i As Long
Dim matchCountTotal As Long
matchCountTotal = 0

Dim currentMatches As Long

For i = LBound(replaceList, 1) To UBound(replaceList, 1)
Dim targetWord As String
Dim replaceWord As String

targetWord = replaceList(i, 0)
replaceWord = replaceList(i, 1)

‘ 検索条件の設定と実行
wdFind.Text = targetWord
wdFind.Replacement.Text = replaceWord

‘ 実行して置換が発生したか判定(Executeは置換成功時にTrueを返す)
‘ すべての該当箇所を置換するため、wdReplaceAllを使用
If wdFind.Execute(Replace:=wdReplaceAll) Then
‘ ※厳密な置換回数を取得したい場合は別ロジックが必要ですが、
‘  今回は「置換が走った」という事実ベースでシンプルに処理します。
End If
Next i

‘ 5. 終了処理とパフォーマンスの復元
Call RestoreEnvironment

‘ 完了ログ
MsgBox “一括置換が完了しました。” & vbCrLf & _
“処理したキーワード数: ” & totalReplaces & ” 項目” & vbCrLf & _
“処理時間: ” & Format(Timer – startTime, “0.00”) & ” 秒”, _
vbInformation, “一括置換エンジン”
Exit Sub

ErrorHandler:
‘ 異常終了時も必ず環境を復元する(これ鉄則)
Call RestoreEnvironment
MsgBox “エラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, _
vbCritical, “致命的なエラー”
End Sub

‘ =================================================================================
‘ 置換マスターデータを返す関数(データ層)
‘ =================================================================================
Private Function GetReplacementMaster() As String()
‘ 配列のサイズを定義 (行, 列) ※0始まり
Dim arr(3, 1) As String

‘ [0, 0]: 検索ワード, [0, 1]: 置換ワード
arr(0, 0) = “旧システム名”: arr(0, 1) = “新クラウド基盤”
arr(1, 0) = “株式会社○○”: arr(1, 1) = “株式会社A”
arr(2, 0) = “平成”: arr(2, 1) = “令和”
arr(3, 0) = “社外秘”: arr(3, 1) = “極秘”

GetReplacementMaster = arr
End Function

‘ =================================================================================
‘ Findオブジェクトの基本設定をカプセル化(ロジック層)
‘ =================================================================================
Private Sub InitializeFindObject(ByRef fObj As Find)
With fObj
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False ‘ 大文字小文字を区別するか
.MatchWholeWord = False ‘ 単語単位で一致するか
.MatchByte = False ‘ 全角半角を区別するか
.MatchWildcards = False ‘ ワイルドカードを使用するか(必要に応じてTrue)
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
End Sub

‘ =================================================================================
‘ アプリケーション環境の復元
‘ =================================================================================
Private Sub RestoreEnvironment()
With Application
.ScreenUpdating = True
.DisplayAlerts = wdAlertsAll
.Calculation = wdCalculationAutomatic
End With
End Sub

—

4. コードの勘所:プロが仕込む3つのこだわり

① `Option Explicit` とエラー時の環境復元

VBAで最も多い事故が、処理途中でエラー落ちした際に `ScreenUpdating = False` や `DisplayAlerts = wdAlertsNone` がそのままになり、Wordが操作不能(フリーズしたように見える状態)になる現象だ。
今回のコードでは、`On Error GoTo ErrorHandler` を経由して、いかなる例外が発生しようとも確実に環境を復元(`RestoreEnvironment`)する設計にしている。

② Findオブジェクトのパラメータ初期化の徹底

Wordの `.Find` は、前回の検索状態(書式設定やワイルドカードフラグなど)をメモリ上に記憶し続けるという極めて厄介な仕様を持っている。
これを防ぐため、`InitializeFindObject` プロシージャ内で `.ClearFormatting` を呼び、フラグを明示的に初期化している。ここを怠ると、「前回の検索条件が残っていて今回ヒットしない」という不可解なバグに悩まされることになる。

③ 二次元配列による将来の拡張性(DB・Excel連携)

今回 `GetReplacementMaster` という独立した関数で配列を生成しているのは理由がある。
実務では「やっぱり置換リストはExcelの管理台帳から読み込みたい」「SQLデータベースから動的に取得したい」という要件に必ず変わる。
その際、メインの置換ループ(`ExecuteBatchReplace`)のコードを1行も変えることなく、`GetReplacementMaster` の中身だけを `Range.Value` やADODBからの取得処理に差し替えるだけで対応できる。これが「保守性の高い設計」の正体だ。

—

5. まとめ

文字列の置換という、一見すると地味で単純な作業であっても、設計のレイヤーを一段引き上げるだけで、コードの寿命とパフォーマンスは劇的に変わる。

「動けばいいや」のスパゲッティコードから卒業し、データとロジックを分離したスマートな配列処理をあなたの武器にしてほしい。明日の業務自動化のクオリティが、確実にワンランク上のものになるはずだ。

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