Visual C++ の正規表現ライブラリで発生するバージョン間での動作の違いについて

こんにちは、Visual Studio サポート チームです。

今回は、Visual C++ の正規表現ライブラリ (regex) で発生するバージョン間での動作の違いについてご案内いたします。

 

Visual C++ では 2008 SP1 で Technical Report 1 (TR1) の regex を取り入れており、以降のバージョンでご利用いただけます。

Visual C++ の regex は C++ 標準に準拠しており、原則としてバージョン間でも互換性がございますので、以前のバージョンの Visual C++ で regex を使用していたコードは、多くの場合新しいバージョンの Visual C++ でもそのまま動作します。

ただし、不具合の修正や標準への準拠などに伴って、バージョン間で動作が異なる部分も稀にございます。特に、regex に限ったことではございませんが、いわゆる処理系依存として C++ 標準に規定されていない部分は、互換性に影響がある変更点としてのご案内なく動作が変わる可能性があります。

 

具体的な例を挙げると、例えば C++ の regex では正規表現の処理で発生したエラーを regex_error クラスのオブジェクトをスローして通知することとなっていますが、error_complexity、error_space、error_stack といった種類のエラーは、同一の入力条件であっても、Visual C++ のバージョンや実行環境が違えば発生状況も異なることがあります。これは、Visual Studio のバージョン間で、バックトラッキングを伴う検索処理の実装や、複雑度の基準の変更があったことなどが影響しています。

特に上記で例に挙げた種類のエラーは、大量のバックトラッキングが発生する可能性があるような正規表現を使用した際に、過去のバージョンでは発生しなかった例外が新しいバージョンでは発生する、あるいはその逆となる、といった状況となった報告もあります。

 

例外がスローされる場合は正規表現の処理結果も得られないためお困りになることもあるかと思います。

Visual C++ では、処理系固有とはなりますが、例外をスローする条件となる基準値の動作を制御するためのマクロとして _REGEX_MAX_COMPLEXITY_COUNT や _REGEX_MAX_STACK_COUNT といったものが用意されています。

特に、Visual C++ のregex は2010 と2012 の間で大きく変更されているため、2010 以前では例外がスローされず実行できた正規表現が 2012 以降では例外がスローされるといった状況が発生する場合があり、こういった状況を回避していただくためにこれらのマクロが利用できます。

なお、Visual C++ の製品仕様として MSDN などで公開されているものではございませんので、利用される際は将来のバージョンで正規表現ライブラリの実装の変更に伴って動作が変わる可能性がある点についてご了承ください。

以下に Visual Studio 2012 から Visual Studio 2017 version 15.4 時点までの regex で定義されているマクロをヘッダー ファイルから抜粋して記載いたします。こちらは、実際に regex のファイルを開いていただければ確認可能です。

  • C:\Program Files (x86)\Microsoft Visual Studio\2017\<Edition>\VC\Tools\MSVC\<Version>\include\regex

#ifndef _REGEX_MAX_COMPLEXITY_COUNT
#define _REGEX_MAX_COMPLEXITY_COUNT      10000000L       /* set to 0 to disable */
#endif /* _REGEX_MAX_COMPLEXITY_COUNT */
#ifndef _REGEX_MAX_STACK_COUNT
#ifdef _WIN64
#define _REGEX_MAX_STACK_COUNT  600L    /* set to 0 to disable */
#else /* _WIN64 */
#define _REGEX_MAX_STACK_COUNT  1000L   /* set to 0 to disable */
#endif /* _WIN64 */
#endif /* _REGEX_MAX_STACK_COUNT */

 

たとえば、一定の複雑度に達したときに regex_error がスローされる動作は、コメントにあるように _REGEX_MAX_COMPLEXITY_COUNT を 0 とすることで無効にすることができます。

#define _REGEX_MAX_COMPLEXITY_COUNT      0
#include <regex>

 

Visual C++ の regex で発生する可能性がある例外については以下のドキュメントをご確認ください。

regex_error Class
< /en-us/cpp/standard-library/regex-error-class >

regex_constants Class
< /en-us/cpp/standard-library/regex-constants-class >