こんにちは! Word VBAの自動化の世界へようこそ。
マクロの記録ボタンを押して「なんとなく動くコードはできたけれど、ここからどう改造していいか分からない…」と悩んでいませんか?
今回は、多くの実務家が頭を悩ませる「一括置換したいけれど、特定の単語だけは絶対に巻き込みたくない!」という課題を華麗にクリアする、一歩進んだテクニックを伝授します。
ここをクリアすれば、あなたのWord VBAスキルは間違いなく中級者の領域に到達します。優しく、そして本質的な部分までしっかり解説していきますので、ぜひ最後までついてきてくださいね!
—
なぜ一括置換の「除外リスト」が必要なのか?
Wordの「検索と置換」機能は非常に強力です。例えば、「古い製品名(A)」をすべて「新しい製品名(B)」に書き換えたいとき、一発で文書全体を置換できるので便利ですよね。
しかし、現場の文書ではこんな悲劇が起こります。
- 「旧製品A」を「新製品B」に一括置換したら、注釈や引用元にある「社外秘:旧製品A」まで勝手に書き換わってしまった。
- 「システム」という言葉を「プラットフォーム」に変えたかったのに、固有名詞の一部まで置換されて文章が崩壊した。
Wordの標準的な `Find.Execute Replace:=wdReplaceAll` は、条件に合致したものを問答無用でなぎ倒していく暴れ馬です。「ここだけは触らないで!」という例外を作るには、VBAのロジックで手綱を引いてあげる必要があります。
—
解決アプローチ:ループ処理と「除外判定」の組み合わせ
一括置換(`wdReplaceAll`)で例外を作るのは、実はWord VBAの仕様上かなり困難です。
そのため、実務で確実な方法をとる場合、「文書内を一つずつ検索(Find)しながら見つけていき、ヒットした場所が除外リストに該当するかどうかを判定して、OKなら置換する」というループ処理を組み立てます。
イメージ図で表すと、こんな感じです。
[文書の先頭から検索]
↓
[ヒット! その単語は?] ──(除外リストにある?)──Yes──> [何もしず次へ]
│
No
↓
[安全に置換を実行!]
少し遠回りに見えるかもしれませんが、この「一歩ずつ確実に対象を吟味するアプローチ」こそが、バグを出さないプロのエンジニアの常道です。
—
実装コード:除外リスト付きスマート置換マクロ
それでは、実際の開発現場でもそのまま使える実用的なコードを公開します。
今回は例として、「テスト」という文字を「検証」に置換したいが、「最終テスト」という単語が含まれている場所だけは絶対に置換したくない、というシチュエーションを想定しています。
VBE(Visual Basic Editor)を開き、標準モジュールに以下のコードを貼り付けてください。
Sub SmartReplaceWithException()
Dim rngTarget As Range
Dim searchWord As String
Dim replaceWord As String
Dim exceptionWord As String
‘ — 設定エリア —
searchWord = “テスト”
replaceWord = “検証”
exceptionWord = “最終テスト” ‘ この単語が含まれる場合は置換しない
‘ ——————
‘ 文書全体を操作するためのレンジオブジェクトを取得
Set rngTarget = ActiveDocument.Content
な
‘ 検索条件の設定
With rngTarget.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = searchWord
.Forward = True
.Wrap = wdFindStop
.MatchCase = False
.MatchWholeWord = False
End With
‘ ヒットし続ける限りループ処理を行う
Do While rngTarget.Find.Execute
‘ 【重要】「検索ワードの少し手前を含めた範囲」を確認し、除外ワードが含まれていないか判定
‘ 例:「最終テスト」の場合、「最終」の部分が直前にあるかをチェックします
Dim rngCheck As Range
Set rngCheck = rngTarget.Duplicate
‘ 除外ワードの文字数分、判定範囲を前に広げる(簡易的な文脈チェック)
rngCheck.Start = rngCheck.Start – (Len(exceptionWord) – Len(searchWord))
‘ もし除外ワードでなければ置換を実行
If rngCheck.Text <> exceptionWord Then
rngTarget.Text = replaceWord
‘ 置換した分、レンジの終端を調整して無限ループを防ぐ
rngTarget.Collapse wdCollapseEnd
Else
‘ 除外対象の場合は、置換せずに次の検索へ進む(無限ループ防止のため1文字進める)
rngTarget.Collapse wdCollapseEnd
rngTarget.Start = rngTarget.Start + 1
End If
‘ 検索レンジを文書の残りの部分に再設定
rngTarget.End = ActiveDocument.Content.End
Loop
MsgBox “除外リストを考慮した置換処理が完了しました!”, vbInformation
End Sub
—
コードの注目ポイントと知見の解説
初心者から一歩抜け出すために、このコードのキモとなる部分をいくつか解説します。
1. `wdFindStop` の重要性
`Find.Wrap = wdFindStop` は、「文書の最後まで検索したら、そこでストップしなさい」という命令です。これを指定しないと、文書の末尾まで行った後に先頭に戻ってしまい、無限ループの沼にハマってWordがフリーズします。安全第一の鉄則です。
2. `rngTarget.Duplicate` による安全な参照
Word VBAでは、`Range`オブジェクトをそのまま操作すると、意図せぬ範囲の拡張やズレが発生しがちです。.Duplicateプロパティを使うことで、「元の位置を維持したまま、安全に検証用のコピー範囲を作る」ことができます。ここがメモリやオブジェクトのライフサイクルを知るエンジニアのテクニックです。
3. 無限ループを防ぐ `Collapse`
条件分岐の中で置換を行わなかった場合、そのまま次のループに行くと「全く同じ場所」を永遠に探し続けてしまいます。そのため、`rngTarget.Collapse wdCollapseEnd` で検索位置を後ろにずらし、プログラムが前に進むように担保しています。
—
陥りやすいエラーと回避のコツ
1. 「文字化けや意図しない箇所が削られる」
→ 複数文字の置換を行う際、レンジの長さをうまく調整できていない場合に起こります。まずは今回紹介したような「単一のキーワードの組み合わせ」から実験してください。
2. 「処理がすごく遅い」
→ 大量のページ(数百ページ)を1文字ずつループさせると、Wordの画面描画(スクリーン・アップデート)が走って重くなります。大量処理を行う場合は、ループの直前に `Application.ScreenUpdating = False` を入れ、最後に `True` に戻すお呪いを入れると爆速になりますよ。
—
まとめ:あなたのWord VBAはもう「記録」だけじゃない
今回は、Word VBAにおける「置換処理中の除外リストの実装」という、一歩進んだ実用テクニックを解説しました。
「マクロの記録」で作ったコードに、こうした条件分岐(If)やループ(Do While)、そしてRangeオブジェクトの操作を組み合わせられるようになると、作れない自動化ツールはなくなります。
「ここをこう変えたらどうなるだろう?」と、ぜひご自身の環境でもコードをいじって遊んでみてくださいね。
あなたのVBAライフが、よりスマートで快適なものになりますように!
