C++の正規表現はロケールが考慮されます。初期状態はCロケールなのでASCIIの範囲にしかマッチしませんが、その他のロケールを使用すれば、たとえばワイド文字で全角文字にマッチすることもあります。

途中の過程を飛ばして述べてしまえば、メタ文字の\s, \d, \wのマッチはstd::localeのctypeで判定されます。言い換えれば、std::localeを引数に取るisspace, isdigit, isalnum関数と同じ判定処理です。

以下のプログラムは\sで全角空白” ”がマッチすることを試すプログラムです。私が試した範囲だとみなtrueを出力します。

#include <iostream>
#include <string>
#include <regex>
 
int main()
{
  std::wregex r;
  r.imbue(std::locale(""));
  r.assign(LR"(\s)");
 
  std::wstring s = L" "; // 全角空白
  std::cout << std::boolalpha << regex_match(s, r) << std::endl;
}

試した環境は以下です。Windowsは日本語版です。UbuntuとFreeBSDでは、LANG=ja_JP.UTF-8とLANG=en_US.UTF-8のそれぞれで試しましたので、実質的には5環境です。

  • Visual C++ (Windows 8.1)
  • GCC, libstdc++ (Ubuntu Linux 12.04.5)
  • Clang, libc++ (FreeBSD 10.1-RELEASE)

一方、\dは実装により結果が異なりました。

#include <iostream>
#include <string>
#include <regex>
 
int main()
{
  std::wregex r;
  r.imbue(std::locale(""));
  r.assign(LR"(\d)");
 
  std::wstring s = L"1"; // 全角数字
  std::cout << std::boolalpha << regex_match(s, r) << std::endl;
}

Visual C++だとtrue、それ以外だとfalseが出力されました。Cロケール以外の挙動は処理系によって異なるので、こういうこともありえてしまうのです。

上記のコードではimbueメンバ関数を使用しましたが、ほかにstd::locale::globalも効果があります。std::regexとstd::wregexオブジェクトの初期値はグローバルロケールであり、imbueで指定しなければそちらになります。main関数の先頭で安易にstd::locale::global(std::locale(“”));としているプログラムでは注意しましょう。

スポンサード リンク

この記事のカテゴリ

  • ⇒ C++の正規表現は全角文字にマッチする(かもしれない)