So-net無料ブログ作成
検索選択

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