SSブログ

C/C++のロケールって、こういうことだったのか [日記]

C++の標準ライブラリにはUnicodeを扱うためのクラスが用意されています。
文字列を表す wstring や、ファイル入出力の wifstreamwofstream など。

さて、
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"));

でバッチリです。


タグ:C++
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

group byとdistinct未使用IDを探す ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。