【入門編】【中級者向け】「検索対象が見つからない」場合に発生する無限ループを回避する終了判定の定石 – Word VBA解析バイブル

スポンサーリンク

こんにちは!Word VBAの世界へようこそ。
マクロの記録ボタンを押して自動生成されたコードを眺め、「よし、動いた!」と喜んでいた時期を通り越し、いざ自力でコードを書き始めると……誰もが一度はこの恐怖を味わいます。

そう、「画面が固まったままフリーズし、タスクマネージャーから強制終了するハプティック(悪夢)」——無限ループです。

特に`Find`オブジェクトを使った文字の検索・置換処理において、終了判定を誤ると、Wordは文書の最初と最後を永遠にぐるぐると回り続けます。

今回は、この無限ループを完全にハントし、実務で安心して使える「堅牢な検索ロジックの定石」を授けましょう。ここをクリアすれば、あなたのWord VBAスキルは間違いなく中級者の領域に到達します。しっかりついてきてくださいね!

—

なぜWord VBAの検索は無限ループに陥るのか?

Excel VBAの`Range.Find`に慣れている人ほど、Word VBAの`Find`オブジェクトでハマりがちです。

Wordの検索(`Selection.Find` または `Range.Find`)は、「文書の末尾まで検索したら、文書の先頭に戻って検索を続ける」というラップアラウンド(折り返し)の性質を持っています。

もし、あなたが「文書の終わりまで来たら終了したい」と考えているのに、その設定を怠ったり、ループの脱出条件(`Loop While` や `Do Until`)を間違えたりすると……。

1. 文書の末尾に到達する
2. 勝手に先頭に戻る
3. またヒットする
4. (1に戻る:無限地獄)

このメカニズムを理解していないことが、暴走の最大の原因です。

—

無限ループを回避する「3つの鉄則」

Word VBAで検索処理を安全に行うためには、以下の3つのステップを必ずコードに組み込みます。

1. 検索範囲(Range)を明確に定義する(`Selection`に頼らない)
2. `Wrap`プロパティを明示的に「ラップしない( wdFindStop )」に設定する
3. `.Execute`メソッドの戻り値(Boolean)をループの判定に使う

これらを完璧に満たす、実務でそのまま使える「模範解答コード」をお見せしましょう。

—

実践!堅牢な検索・置換ループのコードパターン

以下のコードは、文書内の「旧用語」を「新用語」にすべて置換しつつ、絶対に無限ループしない安全設計のプロシージャです。

Sub SafeFindAndReplaceExample()
Dim rngTarget As Range

‘ 1. 検索対象の範囲を「メインストーリーの文書全体」に限定する
Set rngTarget = ActiveDocument.Content

‘ 2. Findオブジェクトの設定
With rngTarget.Find
.ClearFormatting
.Replacement.ClearFormatting

.Text = “旧用語” ‘ 検索する文字列
.Replacement.Text = “新用語” ‘ 置換後の文字列
.Forward = True ‘ 前方に向かって検索
.MatchCase = False ‘ 大文字・小文字を区別しない
.MatchWholeWord = False ‘ 単語単位で探さない

‘ 【最重要】文書の端に達しても自動で折り返さない(これぞ無限ループ防止の盾!)
.Wrap = wdFindStop

‘ 3. .Executeメソッドの戻り値を監視しながらループさせる
‘ .Execute:=wdReplaceAll ではなく、あえて1つずつ処理するループ構造にするのがコツ
Do While .Execute(Replace:=wdReplaceOne) = True
‘ ヒットした瞬間にrngTargetの範囲が「見つかった文字列の範囲」に縮小・移動します。
‘ 必要に応じて、ここでヒットした箇所の書式を変更するなどの追加処理が可能です。

‘ 【重要】次の検索を開始するために、範囲を「ヒットした場所の末尾」から文書の最後まで再定義する
‘ これを行わないと、同じ場所を何度もヒットして無限ループになるか、検索が途中で止まります。
rngTarget.Collapse wdCollapseEnd
Loop
End With

MsgBox “置換処理が正常に完了しました!”, vbInformation, “完了”
End Sub

—

コードの急所を徹底解説!

先輩エンジニアとして、このコードの特に重要なポイントを噛み砕いて解説します。

① `.Wrap = wdFindStop` の絶大な効果

これが今回のテーマの核心です。
`wdFindStop` を指定することで、Wordは「文書の最後まで検索したら、そこでストップしなさい」という命令を受け取ります。これで勝手に先頭へ戻る暴走癖をピタリと抑え込むことができます。

② `Do While .Execute(Replace:=wdReplaceOne) = True` という判定

`.Execute` メソッド自体が、「検索に成功したら `True`、見つからなければ `False`」を返す関数になっています。
つまり、「見つかっている間はループし続けろ、見つからなくなったら自動的にループを抜けろ」という極めてスマートな終了判定がここで完結します。

③ `rngTarget.Collapse wdCollapseEnd` の魔法

ここが一番の玄人ポイントです。
`.Execute` で文字がヒットすると、変数 `rngTarget` は「そのヒットした文字の範囲」に縮小されます。
そのまま次のループに行くと、また同じ場所をヒットしてしまうか、あるいは予期せぬ挙動をします。そのため、ヒットした瞬間に `Collapse wdCollapseEnd`(範囲を末尾の1点に折りたたむ)を実行し、「ここから先をまた探してね」というスタート地点を毎回更新しているのです。

—

ありがちな失敗パターン(反面教師)

初心者の頃、よくやってしまう危険な書き方がこちらです。

‘ 【NG例:絶対に真似してはいけないコード】
Sub DangerousCode()
Selection.Find.Text = “エラー”
Do While Selection.Find.Execute
Selection.Text = “修正済み”
‘ Wrapの設定がない、かつSelectionをそのまま使っているため暴走する危険大!
Loop
End Sub

  • `Selection`(選択範囲)に依存しているため、ユーザーが意図しないカーソル位置から検索が始まり、挙動が不安定になります。
  • `Wrap` の指定がないため、文書の末尾から先頭へループして無限地獄へ突入します。

実務の現場では、画面上のカーソル(`Selection`)を極力触らず、メモリ上の範囲(`Range`)を操作するのがプロの鉄則です。

—

まとめ

いかがでしたか?
「検索対象が見つからない/文書の端に達したときの挙動をどうコントロールするか」を理解すれば、Word VBAの検索処理は怖くありません。

  • 検索は `Selection` ではなく `Range` オブジェクトで行う。
  • `Wrap = wdFindStop` で自動折り返しを禁止する。
  • `.Execute` の戻り値と `Collapse` を組み合わせて安全にループを回す。

ここをクリアしたあなたなら、もうマクロの記録の呪縛からは完全に解放されています。ぜひ実際の業務文書や自動化ツールで試してみてくださいね。

それでは、次回の極限の知見でお会いしましょう!バッチリ使いこなしてください!

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