TL;DR — VBA に
Regexキーワードはありません。VBScript RegExp オブジェクト を作ります。CreateObject("VBScript.RegExp")による遅延バインディングか、参照設定による事前バインディングの どちらかです。プロパティを設定するまで何もしません。.Pattern、そして 役に立たない ほうの値が 既定になっている 2 つ —.Global = False(最初の一致だけ)と.IgnoreCase = False(大文字小文字を 区別)です。それから正しい動詞を選びます。.Testは Boolean を返し、.Replaceは文字列を返し (後方参照は\1ではなく$1)、.Executeは一致のコレクションを返します。そのキャプチャした グループは.Valueではなく.SubMatchesに住んでいます。
Sub RegexBasics()
Dim re As Object
Set re = CreateObject("VBScript.RegExp") ' 遅延バインディング - 参照設定は不要
re.Pattern = "PO-(\d+)" ' グループが数字をキャプチャする
re.Global = True ' 最初の 1 件だけでなく、すべての一致を見つける
re.IgnoreCase = True ' 大文字小文字を区別しない
Dim m As Object
For Each m In re.Execute("po-17 and PO-9004")
Debug.Print m.Value ' PO-17 次に PO-9004 (一致全体)
Debug.Print m.SubMatches(0) ' 17 次に 9004 (キャプチャしたグループ)
Next m
End Sub
この記事で学べること
- 考え方の軸 — regex はキーワードではなく、自分で作るオブジェクト
- 遅延バインディング対参照設定と、そのあとに続くコンパイルエラー
Global = Falseが、最初の一致しか取れないことを意味する理由Test・Replace・Executeがそれぞれ何を返すか- 値を取り出すには
Match.ValueではなくSubMatchesへ手を伸ばす理由 - VBScript のパターンフレーバーが対応するものと、しないもの
考え方の軸:regex はキーワードではなく、自分で作るオブジェクト
ほかのたいていの言語から来ると、regex の演算子か関数を期待します。VBA にはそのどちらもありません。
あるのは COM コンポーネント — VBScript Regular Expressions ライブラリ — で、これをインスタンス化し、
プロパティで配線し、それから呼び出します。だから考え方の軸は「関数を呼ぶ」ではなく「オブジェクトを
構成し、それから問いを投げる」です。以下のいらだちはすべて、実のところ「尋ねる前にプロパティを
設定し忘れた」なのです。
それはまた、いつ手を伸ばす価値があるかも教えてくれます。RegExp は、はしごのてっぺんにいる重量級で、
Like 演算子やただの InStr
の上にいます。準備のコストを払い — 作って、パターンを設定し、スイッチを切り替える — その見返りに、
繰り返し回数、選択、そしてほかにはできない唯一のこと、キャプチャした断片を取り出す ことが手に
入ります。
準備:遅延バインディング対参照設定
オブジェクトを得る方法は 2 つあり、その選択には本当の結果が伴います。
' 遅延バインディング - 移植性があり、参照設定は不要、実行時に解決される
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
' 事前バインディング - 先に参照設定を加えれば、これがコンパイルできる
' Tools -> References -> "Microsoft VBScript Regular Expressions 5.5"
Dim re As New RegExp
事前バインディングは IntelliSense と、わずかに速い呼び出しをもたらしますが、参照設定にチェックが入って
いるときにしかコンパイルできません — そして、参照設定の欠けた相手にブックを送れば、相手は 1 文も実行
されないうちに As New RegExp の行で User-defined type not defined というコンパイルエラーを受け
取ります。遅延バインディング(As Object + CreateObject)には、そんなもろさは一切ありません。実行時に
解決され、参照設定なしで旅ができます。配布するものには遅延バインディングを選びましょう — 移植性は
IntelliSense を失う価値があります。
罠 1:Global が off なので、最初の 1 件しか取れない
.Global は既定で False であり、そのたった 1 つの既定が、最もよくある「regex が壊れている」報告の
2 つを引き起こします。
re.Pattern = "\d+"
re.Global = False ' 既定
Debug.Print re.Replace("a1 b2 c3", "#") ' "a# b2 c3" <- 最初の並びだけ置換された
Debug.Print re.Execute("a1 b2 c3").Count ' 1 <- 最初の一致だけ見つかった
re.Global = True
Debug.Print re.Replace("a1 b2 c3", "#") ' "a# b# c#" <- 今度は全部
Debug.Print re.Execute("a1 b2 c3").Count ' 3
置換が最初の出現だけに触れた、あるいは 3 つ見えているのに検索が 1 件しか見つけなかった — これはほぼ
必ずこれが原因です。「あらゆる場所で」を意味するときは .Global = True を設定しましょう。その隣人
.IgnoreCase も同じように既定で False なので、明らかに違う大文字小文字のテキストに一致すべき
パターンが一致しないなら、たいていは re.IgnoreCase = True の書き忘れです。
罠 2:Test・Replace・Execute は 3 つの異なるものを返す
このオブジェクトは 3 つの動詞を公開していて、その戻り値の型を混同するのが 2 つめの大きなつまずきです。
re.Test(s)は Boolean を返します — パターンはどこかに一致するか? 検証として使います。Likeの正規表現版のいとこです。re.Replace(s, replacement)は String を返します — 各一致(Globalなら)を置換した入力です。 置換文字列の中の後方参照は ドル記号 を使います。$1が最初のキャプチャグループです。\1と 書くとリテラルのバックスラッシュ 1 が挿入され、ほかの言語から来た人がよくやるバグです。re.Execute(s)は MatchCollection を返します — 調べたり取り出したりするためにループで回すMatchオブジェクトのコレクションです。
re.Pattern = "(\d{4})-(\d{2})"
Debug.Print re.Test("2026-09") ' True
Debug.Print re.Replace("2026-09", "$2/$1") ' "09/2026" - $1、$2 がグループ
必要な答えで動詞を選びましょう。Yes/No なら Test、変換した文字列なら Replace、一致したテキストや
その断片が欲しいなら Execute です。
罠 3:取り出すには Value ではなく SubMatches へ手を伸ばす
これが、人をぐるぐる回らせるやつです。.Execute から得る各 Match は、.Value — 一致した 全体 の
テキスト — と、.SubMatches コレクション — かっこでくくった キャプチャグループ、あなたが取り出したい
部分 — を持っています。
re.Pattern = "Invoice #(\d+) dated (\d{4}-\d{2}-\d{2})"
re.Global = True
Dim m As Object
For Each m In re.Execute("Invoice #4471 dated 2026-09-04")
Debug.Print m.Value ' Invoice #4471 dated 2026-09-04 (一致全体)
Debug.Print m.SubMatches(0) ' 4471 (最初のグループ)
Debug.Print m.SubMatches(1) ' 2026-09-04 (2 番目のグループ)
Debug.Print m.FirstIndex ' 0 (入力内の 0 始まりの開始位置)
Next m
その数 が欲しいなら、欲しいのは m.Value ではなく m.SubMatches(0) です — .Value を読んで、なぜ
まだ周囲のテキストが入っているのかと首をかしげるのが、取り出しのバグの第 1 位です。SubMatches は
0 始まりで、一致に参加しなかったグループは空文字列で返るので、インデックスで取りにいく前に re.Test(s)
(かコレクションの .Count)でガードしましょう。
VBScript フレーバー:パターン言語が対応するものと、しないもの
VBA の正規表現は VBScript(RegExp 5.5) フレーバーであって PCRE ではなく、その隔たりが、ほかの
どこかで正規表現の経験を積んだ人をつまずかせます。日常の道具立てには対応しています。\d \w \s と
その否定、量指定子 * + ? {n} {n,m}、選択 a|b、グループ ( )、文字クラス [ ]、そしてアンカー
^ $(それらが行を意味するか文字列全体を意味するかは .MultiLine が決めます)。対応して いない のは、
後読み、名前付きキャプチャグループ、そしてアトミック/強欲でないグループです — それらに頼るパターンは、
あなたの期待どおりにはコンパイルされません。
VBA 固有の救いが 1 つ。VBA の文字列リテラルの中ではバックスラッシュがエスケープ文字で ない ので、
パターンはそのまま書けます — "\\d{4}" ではなく "\d{4}"。C#、Java、JSON とは違い、二重エスケープは
不要です。唯一二重にする必要があるのはリテラルの引用符で、それは VBA 自身の "" です。
意見:regex が儀式に見合うのは、本物の構造があるときだけ
RegExp は VBA で最も強力なテキスト道具であり、最も早まって手を伸ばされがちな道具でもあります。
オブジェクトを作り、パターンを設定し、Global と IgnoreCase を忘れずに設定するのは、れっきとした
儀式です。固定の形やただの Yes/No には、それは要らない儀式です — Like は
読みやすい 1 行ですし、InStr は「このリテラルを
含む」に対してより速いのです。
線を引くべきところは、引き剥がさなければならない構造 です。パターンに可変の繰り返し、本物の選択、
あるいは — これが決め手 — 取り出さなければならないグループ があるとき、regex はそれをやってのける
箱の中の唯一の道具であり、そのぶんの働きをします。件名から注文番号を、ぐちゃぐちゃのタイムスタンプの
部品を、テキストの塊の中のすべてのメールアドレスを。そういうときには手を伸ばし、旅ができるように遅延
バインディングを選び、Global と IgnoreCase を意図して設定し、断片は SubMatches から読みましょう。
それに届かないところでは、はしごを降りるのです。
解析こそが目的のとき — 仕事の方を説明する
regex が正しい道具のときでさえ、パターンが目的であることはめったにありません — 「この列からすべての
請求書番号とその日付を取り出して、2 つのフィールドに分けて」が目的です。そして、キャプチャグループを
持つ VBScript のパターン、Execute のループ、SubMatches の帳簿づけ、そして行がまったく一致しない
端のケース、これらは 1 つの意図のまわりの、たくさんのもろい機械仕掛けです。
ExcelMaster なら、結果を普通の
言葉で — 「B 列から請求書番号と日付を C 列と D 列に取り出して、一致のない行に印を付けて」 — と説明
できます。そして、本物の正規表現エンジンで取り出しを行い、まずファイルをバックアップし、解析できな
かった行を報告する Python を生成します。あなたは何を取り出すかを説明するだけ。パターンも、グループも、
取りこぼしも、それが処理します。
よくある質問
VBA で正規表現を使うには?
VBScript RegExp オブジェクトを作り、そのプロパティを設定し、それからメソッドを呼びます。移植性のある
やり方は遅延バインディングです。Set re = CreateObject("VBScript.RegExp")、それから re.Pattern = "\d+"、
re.Global = True、re.IgnoreCase = True、そして最後に、Boolean・新しい文字列・一致のどれが欲しいかに
応じて re.Test(s)、re.Replace(s, repl)、re.Execute(s) を呼びます。
VBA の正規表現が最初の一致しか置換しないのはなぜですか?
.Global が既定で False だからです。Global が off だと、.Replace も .Execute も最初の一致で
止まります。文字列内のすべての一致に作用させるには、呼ぶ前に re.Global = True を設定します。
VBA の正規表現でキャプチャグループを取り出すには?
re.Execute(s) をループで回し、Match.SubMatches を読みます。SubMatches(0) が最初のかっこのグループ、
SubMatches(1) が 2 番目、と続きます(0 始まり)。Match.Value はグループではなく 一致全体 の
テキストです — グループが欲しかったのに .Value を読むのが、取り出しの最もよくある間違いです。
VBA で正規表現を使うのに参照設定は必要ですか?
事前バインディングのときだけです。Dim re As New RegExp は Tools -> References の「Microsoft VBScript
Regular Expressions 5.5」を必要とし、それが欠けていると User-defined type not defined でコンパイルに
失敗します。遅延バインディング — CreateObject("VBScript.RegExp") を伴う Dim re As Object — は参照
設定が不要で、共有するブックにはより良い選択です。
VBA はどの正規表現フレーバーを使い、後読みに対応していますか?
VBA は VBScript(RegExp 5.5)フレーバーを使います。\d \w \s、量指定子、選択、グループ、文字クラス、
^ $ アンカー、そして $1 による置換の後方参照に対応しています。後読みや名前付きキャプチャグループには
対応していません。また、VBA の文字列リテラルの中ではバックスラッシュが特別でないので、二重エスケープ
なしで "\d{4}" とそのまま書けます。
検証環境
検証環境: Excel 365 (Windows 11), VBA 7.1 — 最終確認 2026-09-04.
関連ガイド: VBA Like · VBA IsNumeric · VBA InStr · VBA Replace · VBA Split
