C/C++のロケールって、こういうことだったのか [日記]
C++の標準ライブラリにはUnicodeを扱うためのクラスが用意されています。
文字列を表す wstring
や、ファイル入出力の wifstream
や wofstream
など。
さて、
Unicodeで書かれたテキストファイルを読もうとこんなコードを書きました。
std::wstring str; std::wifstream in(L"test.txt"); std::getline(in, str);
うまく読めませんでした。
ロケールの問題だろうかと、次の1文を追加してみたのですが、それでもうまくいきません。
std::locale::global(std::locale("japanese"));
とりあえず、読む方は後回しにして、書く方を先に片付けましょう。
std::wofstream out(L"test.txt"); out << L"あいうえお";
………。
何も出力されません。
再度、ロケールを設定してみます。
std::locale::global(std::locale("japanese")); std::wofstream out(L"test.txt"); out << L"あいうえお";
Shift-JISで出力されました(Windows XP + Visual C++)。
あれっ?
ここで、勘違いに気づきました。
wstring
等のUnicode版クラスを使うと、全てがUnicodeで処理されると思っていたのです。
(だから、Unicodeで扱っているのにロケールで japanese を指定するのに違和感を感じていたわけなのですが…)
ですが、そうではなく、
Unicodeになるのは C++で構築された世界の中だけ(と言うか、wstring
等を使っているところだけ)で、外の世界(OS側)とは無関係だったのです。
そして、外の世界の情報を指定するところがロケールなのだと。
ところで、
さっきから wstring
等のクラスをUnicode版 などと称してますが、C++の仕様ではUnicodeと規定されてないんじゃないかな。
大抵の場合、「Unicode」ではなくて「ワイド文字」という言い方で統一されていますし。
1バイトのデータ型(char
)の変数を1つ以上使って1つの文字を表すマルチバイト文字。
1つの文字を1つの変数で表すためサイズの大きいデータ型(wchar_t
)を使うワイド文字。
という分類だけ決まっていて、
実際の文字コードについては「コンパイラにおまかせ」と言ういつものパターンなのでは?
外の世界とはロケールを利用して変換するから、中の世界では自由にして良いということで。
なので、wchar_t
の中身がUnicodeだと決めてコーディングしていると、何かの時に大変な目にあうのかも……。
(補足)きちんとC++の仕様を確認したわけじゃないので、各自で裏を取るように。
閑話休題
wifstream
, wofstream
でUnicodeで書かれたテキストファイルを読み書きするには、どうするか。
「外の世界の情報を指定するところがロケールだ」というのなら、
外の世界の文字コードが Unicode だとロケールで指定したら良いのではないかと思い至りました。
Visual C++ で指定できるロケールは次の形式になっていて、幸いなことにコードページが指定できます。(コードページは文字コードみたいなもの)
locale "言語識別文字列[_国/地域識別文字列[.コードページ]]" | ".コードページ" | "" | NULL
そこでUnicodeのコードページ 1200 を指定します。
std::locale::global(std::locale(".1200")); std::wstring str; std::wifstream in(L"test.txt"); std::getline(in, str); std::wofstream out(L"test2.txt"); out << str.c_str();
コレでUnicodeのファイルを読み書きができるようになりました。
もう、自前で文字コード変換のコードを書かなくても良くなりました \(^o^)/
………
………
………
………
………
………
という夢を見たんだ。
「そんなロケールは知らない」とか言われた (T_T)
ちなみに、文字コードがEUCで書かれたファイルの読み書きは
std::locale::global(std::locale("japanese_japan.20932"));
でバッチリです。
コメント 0