最近の Office 更新後に、これまで普通に動いていた Excel VBA や VBScript の正規表現処理が「Microsoft Visual C++ Runtime Library – ASSERTION FAILED」のダイアログとともにクラッシュする――そんな現象に悩んでいませんか。本記事では、特に VBScript.RegExp を使った先読み(lookahead)パターンで顕在化している不具合の内容と、実務で取りうる安全な回避策・検証手順を詳しく解説します。
VBScript.RegExp で「ASSERTION FAILED」が起きる問題の概要
2025 年夏以降、Microsoft 365 アプリ(Excel / Access / Word / Outlook など)で VBScript.RegExp を使うと、以下のような ASSERTION FAILED ダイアログが突然表示され、アプリごと落ちる事例が世界的に報告されています。
- タイトル:
Microsoft Visual C++ Runtime Library - メッセージ:
Assertion failed! - ファイル名:
regexpbase.cxxやrtre.cxxなど VBA ランタイム内部のソースファイル - ボタン:
[Abort] [Retry] [Ignore]など
通常の VBA エラー(実行時エラー 5 など)と違い、これは VBA のさらに下にあるランタイムが落ちているため、エラー ハンドラ(On Error)で捕まえることもできません。多くの場合、ユーザー操作ではどうにもならず、アプリを終了するしかなくなります。
よく報告されている共通点
各種フォーラムや Q&A、GitHub の議論をまとめると、次のような共通点があります。
- Office バージョンが 2508 以降(例:Build 19127.20154 / 19127.20174 など)
VBScript.RegExpを利用- 早期バインディング:
Dim re As RegExp : Set re = New RegExp - 遅延バインディング:
Set re = CreateObject("VBScript.RegExp")
- 早期バインディング:
- 先読み / 否定先読み を含むパターンで特に再現性が高い
.*(?=abc)\b(the|-|an|this|that|those|these)\b(?=\s+is)([^_]+(?=_))など
.Test/.Execute/.Replaceのいずれでも発生しうる
つまり、「特定のパターンを書き間違えた」というよりは、VBScript.RegExp コンポーネント側のバグとして扱うのが妥当です。
Office 2508 で何が変わったのか?(VBScript 廃止と RegExp の統合)
このタイミングで問題が顕在化している背景には、Microsoft による VBScript 廃止 と、それに伴う RegExp の VBA への統合があります。
- VBScript は Windows の「Feature on Demand」として段階的に無効化・削除される予定
- 従来、VBA からの正規表現は
vbscript.dll(VBScript.RegExp)に依存 - Office バージョン 2508(Build 19127.20154)以降では、VBA ランタイムに RegExp クラスが組み込みに
RegExp/Match/MatchCollection/SubMatchesが VBE の標準クラスに- 参照設定無しでも
Dim re As RegExp : Set re = New RegExpが通る CreateObject("VBScript.RegExp")も内部的に新しい実装にリダイレクトされる
この「内部実装の切り替え」に伴って、以下の 2 系統のバグが世界中で報告されました。
- .Replace の第 2 引数(置換文字列)を ByRef で渡したときの ASSERTION FAILED
→ こちらは Office 2508 Build 19127.20192 で修正済み。 - 先読み / 否定先読みを含むパターンで .Test / .Execute / .Replace が ASSERTION FAILED
→ Microsoft 公式・コミュニティ双方でバグとして認識され、GetObject("", "VBScript.RegExp")を使う暫定回避策が共有されています。
以降では、特に 2 つ目の「先読みバグ」への実務的な対処を中心に説明します。
最小再現コードと回避コード
最小再現例(落ちるコード)
Office 2508 以降の一部ビルドで、次のような ごく単純なコードでも ASSERTION FAILED が発生することが確認されています。
Option Explicit
Sub Repro_AssertFailed()
' 参照設定: Microsoft VBScript Regular Expressions 5.5
Dim re As RegExp
Set re = New RegExp ' ← ここで作ったインスタンスが問題になる
re.IgnoreCase = True
re.Global = True
re.Pattern = ".*(?=abc)" ' 単純な先読み付きパターン
Debug.Print re.Test("1234abcxy") ' マッチすると ASSERTION FAILED ダイアログが出る環境がある
End Sub
回避例(GetObject を使う)
同じパターンでも、正規表現オブジェクトの作り方を GetObject("", "VBScript.RegExp") に変えると、多くの環境でクラッシュしなくなることが報告されています。
Option Explicit
Sub Repro_Workaround()
Dim re As Object ' RegExp 型でも良いが、Object 推奨
Set re = GetObject("", "VBScript.RegExp")
re.IgnoreCase = True
re.Global = True
re.Pattern = ".*(?=abc)"
Debug.Print re.Test("1234abcxy") ' 問題のビルドでも落ちないケースが多い
End Sub
ポイントは「New でインスタンスを作らない」ことです。
Dim re As RegExp : Set re = New RegExp(NG)Dim re As Object : Set re = GetObject("", "VBScript.RegExp")(OK なケースが多い)
実務で最優先すべき回避策:GetObject で RegExp を生成する
GetObject を使う理由(内部的な挙動の違い)
GetObject は「既存の COM オブジェクトに接続する/事前にロード済みのサーバーを取得する」ための関数で、New や CreateObject とは内部の初期化ルートが異なります。その結果、内部状態が変わり、たまたまバグを踏まなくなると考えられていますが、公式な仕様は公開されていません。
重要なのは、「恒久策と言い切れないが、現時点では最も副作用が少ない実用的ワークアラウンド」という位置付けで捉えることです。
推奨するラッパー関数のパターン
大規模プロジェクトであれば、いきなり全コードを書き換えるのではなく、まず RegExp 生成用のラッパー関数を作ると管理が楽になります。
' 共通モジュール(例えば modRegex)に配置
Public Function NewSafeRegExp() As Object
' 将来の修正に備えて、インスタンス化のロジックを 1 箇所に集約
Set NewSafeRegExp = GetObject("", "VBScript.RegExp")
End Function
既存コードは次のように段階的に置き換えていきます。
' Before(従来コード)
Dim re As RegExp
Set re = New RegExp
' After(暫定回避策)
Dim re As Object ' RegExp 型のままでも動作しますが、互換性の観点で Object 推奨
Set re = NewSafeRegExp()
この方式にしておくと、将来 Microsoft がバグを修正した後に、NewSafeRegExp の中身だけを変更して「元の New 方式に戻す」といった切り替えも簡単にできます。
早期バインディングを使う場合の注意点
先読みバグは 早期バインディングでも遅延バインディングでも再現する例が報告されています。ただし「インスタンス化を GetObject に変えると安定した」ケースが多いため、早期バインディング派でも以下のように書き換えるのが現実的です。
' 参照設定: Microsoft VBScript Regular Expressions 5.5
Dim re As RegExp
Set re = GetObject("", "VBScript.RegExp") ' New は付けない
この場合も Dim ... As New RegExp と書く必要はありません。New を付けると無駄に別のインスタンスを生成してしまうだけなので、避けるのが良いでしょう。
GetObject 回避策をまとめた早見表
| 観点 | New / CreateObject | GetObject(“”, “VBScript.RegExp”) |
|---|---|---|
| ASSERTION FAILED 発生確率 | 先読みパターンで高い | 多くの報告で低い/未発生 |
| コード修正の工数 | 現状維持 | 生成部分の書き換えのみで済む |
| 将来の互換性 | バグ修正後は本来こちらが標準 | 仕様外動作に依存するため暫定策と考えるのが安全 |
| おすすめ度(現時点) | ×(問題のビルドでは危険) | ◎(まず最初に試すべき回避策) |
パターンを書き換えて先読みを避けるテクニック
GetObject を使っても不安定な場合、あるいは環境差異を極力減らしたい場合は、正規表現パターン自体から先読みを取り除く方向も検討に値します。
例 1:.*(?=abc) を非貪欲キャプチャに書き換える
「abc の直前まで」を取りたいだけなら、次のように 非貪欲(lazy)なキャプチャに置き換え可能です。
| 目的 | 元のパターン(先読みあり) | 代替パターン | 備考 |
|---|---|---|---|
abc の直前までを取得 | .*(?=abc) | (.+?)abc | グループ 1 が「abc の直前まで」を表す |
Dim re As Object, m As Object
Set re = NewSafeRegExp()
With re
.Global = False
.Pattern = "(.+?)abc"
End With
Set m = re.Execute("1234abcxy")
If m.Count > 0 Then
Debug.Print m(0).SubMatches(0) ' => "1234"
End If
例 2:\b(the|-|an|this|that|those|these)\b(?=\s+is) を書き換える
「the や this などに続いて is が控えている単語だけを対象にしたい」というケースでは、先読みを外して次のように書けます。
| 目的 | 元のパターン | 代替パターン | 備考 |
|---|---|---|---|
is の直前の限定語を拾う | \b(the|-|an|this|that|those|these)\b(?=\s+is) | \b(the|-|an|this|that|those|these)\b\s+is | マッチ全体は「単語+空白+is」になる |
置換時に 後続の " is" を再構成しないようにすれば、元の意図に近い動作を再現できます。
' 例:限定語のみを強調表示するイメージ
With re
.Global = True
.Pattern = "\b(the|-|an|this|that|those|these)\b\s+is"
End With
Dim src As String
src = "This is a pen. That is a pencil."
' マッチ全体を $1 に置き換えるイメージで処理を組む
' (実際には RegExp.Replace ではなく、Execute の結果から $1 の部分だけを加工する方が安全)
完全な等価変換にはならない場合も多いため、機能面と安全性のバランスを見ながら、局所的にパターンを簡略化する判断が必要です。
パターン書き換えのコツ
- 「境界を保ちたい」だけなら非貪欲キャプチャ+固定文字列 で置き換えられないか考える
- どうしても先読みが欲しい箇所を 文字列処理(InStr / Mid)で補完 するハイブリッド戦略も検討
- テスト用の小さなマクロを作り、「元パターン」「書き換え後パターン」の両方で同じテストケースを実行し、差分を確認する
Office をロールバックして安定ビルドを使う
業務上どうしても先読みを多用せざるを得ない、あるいは 大規模な正規表現を短期間で書き換えるのが現実的でない 場合、既知の安定ビルドにロールバックするという選択肢もあります。
報告の多いバージョンと状態
| Office バージョン / ビルド | 状態(コミュニティ報告ベース) | 備考 |
|---|---|---|
| 2506(例:16.0.18925.20216) | RegExp 正常(ASSERTION FAILED 報告なし) | ロールバック先として使われることが多い |
| 2507(例:16.0.19029.20208) | RegExp 正常 | 多くのユーザーが「ここに戻したら直った」と報告 |
| 2508 初期ビルド(19127.20154 / 20174 など) | .Replace / 先読みで ASSERTION FAILED 多数 | 問題の中心となったビルド群 |
| 2508(19127.20192) | .Replace の ByRef バグは修正 | 先読み系のクラッシュは一部環境で継続 |
| 2509(例:16.0.19231.20138) | 多くのケースで先読みクラッシュも解消との報告 | 一部では依然として問題パターンありとの声もあるため要検証 |
最新のチャンネルとビルドによって状況が変わるため、検証用マシンで自社のマクロを実際に流してみることが重要です。
ODT(Office Deployment Tool)を使ったロールバック手順(概要)
- Office Deployment Tool をダウンロード
- Config.xml を作成(同じフォルダに配置)
<Configuration> <Updates Enabled="TRUE" TargetVersion="16.0.19029.20208" /> </Configuration>※TargetVersionには戻したいバージョン(例:2507 相当)を指定します。 - 管理者権限でコマンドプロンプト起動し、次を実行
setup.exe /configure config.xml - ロールバック後、自動更新を一時停止(Excel > ファイル > アカウント > 更新オプション > 更新を無効化)
ロールバックは セキュリティ更新や他機能の修正も巻き戻すため、社内ポリシーやセキュリティ担当者との調整が必須です。また、将来のビルドで問題が解消されたら、必ず再度アップデートを検討してください。
代替の正規表現エンジンを使う(最終手段)
どうしても安定しない場合、VBScript.RegExp に依存しない正規表現エンジンを採用するのも一案です。
- .NET の
System.Text.RegularExpressions.Regexを COM 経由で呼び出す - VBA で実装された純粋な正規表現エンジンを利用する(処理速度は遅くなりがち)
ただし、これらは次のようなデメリットがあります。
- COM ラッパーの作成や配布が必要で、初期コストが大きい
- 既存コードとの互換性検証に時間がかかる
- Regex の仕様差(後読み対応・Unicode 対応など)を理解しておく必要がある
そのため、短期的なトラブルシューティングというより、中長期のリファクタリング プロジェクトとして計画した方が現実的です。
既存プロジェクトで確認しておきたいチェックリスト
ここまでの内容を踏まえて、実務でまず確認しておきたいポイントをチェックリスト形式で整理します。
| 項目 | 確認内容 |
|---|---|
| RegExp の生成方法 | New RegExp や CreateObject("VBScript.RegExp") を使っていないか?できるだけ GetObject("", "VBScript.RegExp") に置き換える。 |
| 先読みパターンの有無 | コード中に (?= / (?! が含まれる箇所を洗い出し、重要度の高いものから動作確認。 |
| 利用メソッド | .Test / .Execute / .Replace それぞれで再現しないか確認。特に .Replace は第 2 引数の ByRef/ByVal に注意。 |
| Office バージョンの把握 | ユーザーごとの Office ビルド(2507 / 2508 / 2509…)を一覧化し、どの環境で問題が出ているか整理。 |
| テストマクロの整備 | 重要な正規表現ごとに簡単なテストマクロを用意し、Office 更新前後で回す仕組みを作る。 |
| ログ出力 | マッチ結果や入力データをログに出し、どの入力で落ちたか後から追えるようにする(ASSERTION FAILED でも、直前の入力はログから追える)。 |
| フィードバック送信 | Excel の「ヘルプ > フィードバック」から再現手順を送る。報告数が多いほど修正優先度が上がる。 |
簡易スキャン用のサンプル(VBProject から RegExp 利用箇所を列挙)
トラスト センターで「VBA プロジェクト オブジェクト モデルへのアクセスを信頼する」を有効にしている前提ですが、次のようなスクリプトで VBScript.RegExp 利用箇所をざっと洗い出すこともできます。
Sub ListRegExpUsage()
Dim comp As Object, codeMod As Object
Dim i As Long, line As String
For Each comp In ThisWorkbook.VBProject.VBComponents
Set codeMod = comp.CodeModule
For i = 1 To codeMod.CountOfLines
line = codeMod.Lines(i, 1)
If InStr(1, line, "VBScript.RegExp", vbTextCompare) > 0 _
Or InStr(1, line, "RegExp", vbTextCompare) > 0 Then
Debug.Print comp.Name & ":" & i & " " & line
End If
Next i
Next comp
End Sub
ここで列挙された箇所から、優先度の高い順に GetObject 化・パターン見直しを進めていくと効率的です。
よくある質問(FAQ)
Q. GetObject を使えば、今後もずっと安全ですか?
A. 「少なくとも現時点では有効な暫定回避策」と考えるのが妥当です。Microsoft が内部実装を再び変更した場合、GetObject 経由でも挙動が変わる可能性はゼロではありません。そのため、
- ラッパー関数を挟んでおき、いつでも差し替えられるようにする
- Office 更新時はテストマクロを回す
といった「変化を受け止める仕組み」を用意しておくことをおすすめします。
Q. 参照設定「Microsoft VBScript Regular Expressions 5.5」は外してしまって良い?
A. Office 2508 以降では、参照設定を追加しなくても RegExp 型が使えるようになりました。とはいえ、
- 古い Office バージョン(2507 以前)もサポートする必要がある
- VB6 や純 VBScript からも同じパターンを使っている
といった事情があるなら、当面は参照を残しておくのが安全です。最終的には、対象となる Office バージョン ポリシーを決めたうえで整理すると良いでしょう。
Q. Access や Word、Outlook VBA でも同じ問題が起きますか?
A. はい。いずれも 同じ VBA ランタイム(VBE)を共有しており、Office バージョン 2508 以降では同様の RegExp 統合が行われています。Access 用の情報として報告されたバグであっても、Excel / Word / Outlook など他アプリでも同じように再現しうる点に注意してください。
Q. VBScript(cscript / wscript で動かす .vbs)でも問題になりますか?
A. このバグは 主に Office アプリ内の VBA から VBScript.RegExp を利用したときに報告されています。純粋な .vbs スクリプトだけで動かしている場合は、Windows 側の VBScript 実装に依存するため、挙動が異なる可能性があります。ただし、今後 VBScript 自体が無効化/削除されていくことを考えると、早めに「VBA 内蔵 RegExp」または代替エンジンへの移行を検討するのがよいでしょう。
まとめ:VBScript.RegExp ASSERTION FAILED への推奨対応フロー
最後に、本記事の内容を「実務でどう動くか」の観点で整理します。
- まずはコード側での回避
New RegExp/CreateObject("VBScript.RegExp")をやめ、GetObject("", "VBScript.RegExp")でインスタンス化する- 重要な先読みパターンは、非貪欲キャプチャなどで書き換えできないか検討する
- それでも業務に支障が出る場合
- 検証用環境で最新ビルド(例:2509 以降)で問題が解消していないか確認する
- 必要に応じて、2506 / 2507 など既知の安定バージョンにロールバックし、自動更新を一時停止する
- 中長期的な視点
- VBScript 廃止のロードマップを踏まえ、VBA 内蔵 RegExp への移行方針を決める
- どうしても高度な Regex が必要なら、.NET Regex など別エンジンの採用も検討する
- テストマクロ&ログ出力を整備し、Office 更新のたびに自動チェックできる仕組みを作る
- フィードバックと情報収集
- Office アプリの「ヘルプ > フィードバック」から、再現手順付きで報告する
- 公式ブログやコミュニティ(Access / Excel の技術ブログや Q&A)をウォッチし、修正状況を追う
VBScript.RegExp は、VBA における文字列処理の「心臓部」といっても過言ではありません。だからこそ、一時的なバグに振り回されないよう、安全な回避策(GetObject)+テスト+バージョン管理を組み合わせて、業務システムを安定して運用していくことが重要です。

コメント