🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

Excel VBA の Replace — テキストを置換、その引数に潜む罠

|

Excel VBA の Replace — テキストを置換、その引数に潜む罠

検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-09

要点(TL;DR)Replace は部分文字列を見つけて別のものに入れ替えます — 一度の処理で、すべての一致を。コードで書く Ctrl+H であり、元を変更せず 新しい 文字列を返します。

Sub ReplaceDemo()
    Dim s As String
    s = "2026-04-01"
    Debug.Print Replace(s, "-", "/")     ' 2026/04/01   ← すべてのダッシュ、1 回で
    Debug.Print s                        ' 2026-04-01   ← 元はそのまま
End Sub

トラブルが潜む完全な構文:

Replace(expression, find, replace, [start], [count], [compare])
'                                    ⚠ 罠        vbTextCompare = 大文字小文字を無視

メンタルモデル:これは Ctrl+H であって「最初の1つだけ置換」ではない

Excel で Ctrl+H を押して「すべて置換」をクリックすると、一致するものすべてを一度に変えます。VBA の Replace 関数は既定でまさにそれをします — 「次を検索して聞いてくる」モードはありません。文字列を渡すと、すべての 出現を入れ替えたコピーを返します。

このモデルから2つが直接導かれます。1つ目、元の変数には触れません — Replace は結果を 返す 関数なので、必ず受け取る必要があります(s = Replace(s, …))。2つ目、すべてを変えるので、Replace は 一括変換 に適した道具です — すべての区切りを正規化、すべての $ を除去、すべての "N/A""" に — そして 特定の1つ だけ変えたいときには誤った道具です。あとでここに戻ります。「最初の1つだけ変える」という道こそ、Replace の引数がデータ損失の罠に変わる場所だからです。

唯一の鉄則:Replace は 既定で大文字小文字を区別する

これは「Replace が何もしない」という質問の半分の裏にある鉄則です。

既定で ReplacevbBinaryCompare(厳密な大文字小文字)で一致させます。Replace("Hello", "h", "J")"Hello" を変えずに返します。大文字の H は小文字の h ではないからです。

大文字小文字を問わず一致させるには、6 番目の引数を明示的に渡す必要があります:

Debug.Print Replace("Hello", "h", "J")                      ' Hello   (一致せず!)
Debug.Print Replace("Hello", "h", "J", , , vbTextCompare)   ' Jello   (H に一致)

カンマが2つ空いていることに注目 — startcount を飛ばして compare に届かせています。この不格好さは言語からのヒントです。これら中間の引数は、ふつう触らない方がよいものなのです。それが本当の罠につながります。

データを食う罠:start は結果を切り詰める

誰もが start 引数を「この位置から検索を始める」と読みます。確かにそうします — そして、それより前のすべてを捨てます。 Replace が返す文字列は start から 始まる のです:

Debug.Print Replace("ABCDEF", "C", "x", 3)
' 期待: "ABxDEF"
' 実際: "xDEF"        ← "AB" が消えている

位置 3 から始めるとは、返り値が 3 文字目("CDEF")から始まり、そこに置換を適用 → "xDEF" という意味です。最初の 2 文字は飛ばして保持されるのではなく、出力から完全に落ちます。1回限りなら明白ですが、5 万セルを処理する関数の奥に埋もれると、すべての値を静かに短くし、合計が合わなくなって初めて気づきます。

count 引数(最大置換回数)は破壊力こそ低いものの、本当の狙いが「最初の1つだけ」のとき、まさに望まない形で start と相互作用します。誠実な鉄則:startcount は既定のままにする。 本当に最初の出現だけ置換したいなら、count に手を伸ばさず、InStr で位置を見つけて Mid で組み直します:

' 接頭辞を失わずに最初の "-" だけ置換
pos = InStr(s, "-")
If pos > 0 Then s = Left(s, pos - 1) & "/" & Mid(s, pos + 1)

Replace(s, "-", "/", , 1) より長いコードですが、文字列の先頭を食いません。

もう1つの Replace:Range.Replace は文字列でなくシートを変える

Excel VBA には全く別物の「Replace」が2つあり、取り違えると何時間も無駄にします。関数Replace(...))はメモリ上の文字列を変換します。メソッドRange.Replace ...)はワークシートそのものへの置換です:

' メソッド — セルを直接書き換え、列全体を1回で、ループ不要
Columns("B").Replace What:="N/A", Replacement:="", _
                     LookAt:=xlWhole, MatchCase:=False

狙いが「セル範囲にまたがってこのテキストを変える」なら、文字列関数をセルごとにループで呼ば ない でください。Range.Replace は範囲全体を一発で処理し、大きなシートで劇的に速いです。すでに変数に保持している値を操作するときだけ、文字列関数に手を伸ばします。

意見:あの省略可能な引数は機能でなく罠

VBA の Replace は引数が6つあり、その設計は静かに「3つを使え」と告げています。expressionfindreplace — はい。compare — 大文字小文字が問題になるとき、ときどき。startcount — ほぼ決して。その挙動(結果の切り詰め、不格好な相互作用)が誰をも驚かせ、データを静かに壊すからです。

私の経験則:Replace の 4 番目か 5 番目の引数を打ち込んでいるなら、止まって、本当に欲しいのは InStr + Mid ではないかと問う。 10 回中 9 回は「最初の出現を置換」か「ここ以降を置換」が狙いで、位置ベースの処理の方が明快かつ安全です。カンマ2つ飛ばしの vbTextCompare 呼び出しが、筋肉記憶に残す価値のある唯一の「上級」形です。

使い分け

こうしたい… 使うもの 注意点
文字列内のすべての出現を入れ替え Replace(s, a, b) 返り値を受け取る:s = Replace(...)
同上、ただし大文字小文字を無視 Replace(s, a, b, , , vbTextCompare) start/count を飛ばすカンマ2つ
ワークシートのセルにまたがる置換 Range.Replace What:=… 関数でなくメソッド — ループ不要
最初の出現だけ置換 InStr + Left/Mid count/start は切り詰め・想定外
部分文字列を完全に除去 Replace(s, junk, "") 空文字列で置換

よくある Replace のミス(と直し方)

症状 原因 直し方
Replace が「何もしなかった」 大文字小文字の不一致(既定は区別あり) 6 番目の引数に vbTextCompare
元の文字列が変わらない 返り値を受け取らなかった s = Replace(s, …) — コピーを返す
出力の先頭文字が欠ける start 引数を使った start をやめる — 結果を切り詰める
全一致を置換、1つだけ欲しかった Replace は既定で全置換 InStr + Mid で最初を狙う
大きなシートで遅い 関数を各セルでループした 範囲に Range.Replace を1回
「引数は省略できません」 findreplace を忘れた 最初の3引数はすべて必須

テキスト整形が本業になったら — 「結果」を伝える

Replace 1つは些細です。本物の整形はその積み重ね — $ を除去、桁区切りを入れ替え、"N/A" を正規化、日付のダッシュを直し、残りを Trim — をシート全体に、正しい順序で、正当にドル記号を含む値を壊さずに適用します。ExcelMaster Agent なら、最終状態を — 「C 列を整形:通貨記号を除去、N/A を空白に、日付書式を統一」 — と述べるだけで、安全に実行し、まずファイルをバックアップしてから動く Python を生成します。start 引数の不意打ちもありません。無料で試す →

関連ガイド

FAQ

VBA の Replace は何をする関数ですか? Replace 関数は、ある部分文字列のすべての出現を別のものに入れ替えた文字列のコピーを返します。Replace("a-b-c", "-", "/")"a/b/c" を返します。元の変数は変えません — 結果を代入し直す必要があります。

VBA の Replace が動かない/何も置換しないのはなぜ? 最も多い原因は大文字小文字です。既定で Replace は大文字小文字を区別する(vbBinaryCompare)ため、Replace("Hello", "h", "J") は一致しません。6 番目の引数に vbTextCompare を渡せば区別せず一致します。次に多いのは返り値を受け取り忘れることです。

VBA の Replace を大文字小文字を区別しないようにするには? compare 引数に vbTextCompare を加えます:Replace(s, find, repl, , , vbTextCompare)。カンマ2つは startcount を飛ばすためで、これらはふつう既定のままにすべきです。

VBA の Replace で文字列の先頭が切れるのはなぜ? start 引数を渡したからです。Replacestart から 始まる 文字列を返します — その位置より前は保持されず、捨てられます。先頭を失わずに文字列内で置換するには、start を省くか、InStr + Mid を使います。

Replace と Range.Replace の違いは? Replace(...) はメモリ上の文字列を変換する関数です。Range.Replace ... はワークシートのセルに対し、範囲全体を1回の呼び出しで検索・置換するメソッドです。シートを編集するならメソッド、文字列変数を編集するなら関数を使います。