char32_t だと regex が使えない
C++0x では UCS に対応し、専用の型やリテラルの記法が導入されました。その関係で、以下の点について調査を行っていました。
- C++0x で UCS を UTF-32 として扱う型
char32_t
,u32string
およびリテラルU"..."
と、 libiconv の UCS-4-INTERNAL との間に互換性はあるか。 - C++0x で新たに追加された正規表現ライブラリ
<regex>
は利用可能か。 <regex>
が利用できない場合、 Boost.Regex を用いて UTF-32 文字列を処理することは可能か。
これらの調査は、すべて otoco のコアデータを扱うプログラム内で内部文字列に UTF-32 を採用することを前提としたものでした。
結論から言うと、内部文字列に UTF-32 を採用することは、現時点では諦めざるを得ない、ということになりました。\(^O^)/ 以下、その解説です。
1 については、互換性に問題がないことを確認しました。
2 についてですが、 GCC 4.5 の標準 C++ ライブラリでは、 <regex>
のヘッダファイルは存在するものの、ライブラリの実体がまだ用意されていない、という状態のようでした。
で、 3 についてなのですが… 簡単のため、以下のサンプルを見てみることにします。
#include <string> #include <boost/regex.hpp> using namespace std; typedef boost::basic_regex<char32_t, boost::regex_traits<char32_t> > u32regex; typedef boost::match_results<u32string::const_iterator> u32smatch; int main() { u32string text(U"C++0x のせかいへようこそ!!"); u32string modified; u32regex reg(U"せかい"); u32smatch match; while (boost::regex_search(text, match, reg)) { modified += match.prefix().str() + U"世界"; text = match.suffix().str(); } modified += text; return 0; }
このサンプルは、期待通りに動作しても、何もしません。UTF-32 の文字列 U"C++0x のせかいへようこそ!!"
の U"せかい"
を U"世界"
に置換する、という処理を内部で行うだけです。 u32string
に対応した iostream
があったとして、 UTF-32 をそのままコンソールやファイルに出しても不親切なだけなので、出力までやるなら libiconv と組み合わせるべきですが、プログラムが複雑になるので、ここではそこまで示していません (実際にはそこまで試そうとしていたのですが…)。
で、このプログラム、実際はどうなるのかというと、 GCC 4.5 でコンパイルは通るものの、実行すると、 u32regex
オブジェクト (これは boost::basic_regex<char32_t, boost::regex_traits<char32_t> >
のシノニムですね) のコンストラクタが std::bad_cast
例外を送出します。どうやら、 Boost.Regex は char32_t
、すなわち 32bits 以上の整数型を文字コードに使用するということ、を想定した作りにはなっていなかったようなのです。よーするに char
と wchar_t
しか想定していなかったんですね (ん? でも GCC の wchar_t
は uint32_t
だったような…)。
GCC の標準 C++ ライブラリが <regex>
のライブラリを実装するのを悠長に待っても居られないので、方針を転換し、内部文字列は UTF-8 で実装せざるを得なさそうです。一応、UTF-8 は文字の先頭オクテットか否かを判断するのが容易なので (0×80≦n≦0xBF 以外なら先頭オクテット)、文字境界の特定も文字数カウントも一度関数を書いてしまえば ok なのですが…。
2010 年 9 月 22 日 by 村山 俊之
2010 年 9 月 22 日 11:55 PM
[...] はらぺこ日誌 株式会社はらぺこ 公式ブログ « char32_t だと regex が使えない [...]
2011 年 9 月 21 日 11:27 AM
[...] なんとなく Virtual Box から利用している Ubuntu のアップグレードなどをして、そこからなんとなく「やっぱり Long Time Release 版の Ubuntu もテスト環境に持っておきたいよなぁ」などと思いつつ Virtual Box ディスクイメージを追加でこさえて、 Boost ライブラリのセットアップなどもしつつ動作チェックも兼ねて昔書いた記事なんぞを掘り起こしておりましたら、そこに書かれた内容に関連して、そういえば Boost.Regex も ICU ライブラリと組み合わせれば Unicode に対応できたはずだよなぁなどということが気になりだしてしまいまして、いろいろ試しているうちに、以下のようなサンプルコードが問題なく動作してしまうことを発見してしまったのでメモしておこうかと思った次第なのであります。ああ、なんだかこちらのブログも口調が個人ブログや普段の Twitter とかでのそれに似てきてしまいました (^_^;A 。 [...]
2011 年 12 月 27 日 3:00 PM
[...] もちろん、basic_regex はテンプレートクラスなのですから、自分でテンプレートパラメータを指定してあげればうまくいきそうに見えます。しかし、同様の試みを Boost.Regex について行った際には、 std::bad_cast 例外が送出され…。将来的には、あるいは処理系によってはうまく動かせる (ようになる) のかもしれませんが、あまり期待は持たない方が良いかもしれません…。 [...]