VC.NET ~ 文字コード変換

前置き

ここでは、Stringクラスの文字列をシフトJISやUTF-8のバイト配列へ変換するコードを示します。

Javaでも同様ですが、.NETのStringクラスやCharクラスは、文字をUTF-16で管理しています。これらを適切に扱うには、Unicodeに関する知識が欠かせません。こちらの記事も参考にして下さい。

本文

準備

バイト配列をウィンドウに表示できるように、次の関数を用意しました。

String^ hexString(array<Byte>^ ba) {
  String^ hs = "";
  for each ( Byte b in ba ) hs += b.ToString("X2") + ":";
  return hs;
}

文字コード変換

文字コード変換には、System::Text::Encodingクラスを使います。何種類かのEncodingオブジェクトがあらかじめ用意されている他、文字コード名やコードページを指定して新規にEncodingオブジェクトを作成することもできます。

String^ str = "漢字";

// StringをUTF-8でエンコード。
Encoding^ utf8 = Encoding::UTF8;
array<Byte>^ ba = utf8->GetBytes(str);
mCodeLabel->Text = hexString(ba);           // "E6:BC:A2:E5:AD:97:"

// StringをシフトJISでエンコード。
Encoding^ sjis = Encoding::GetEncoding("shift_jis");  // 932でも可。
ba = sjis->GetBytes(str);
mCodeLabel->Text = hexString(ba);           // "8A:BF:8E:9A:"

// シフトJISのバイト配列を、EUC-JPへ変換。
Encoding^ euc = Encoding::GetEncoding(20932);         // "euc-jp"でも可。
ba = Encoding::Convert(sjis, euc, ba);
mCodeLabel->Text = hexString(ba);           // "B4:C1:BB:FA:"

// EUC-JPのバイト配列をStringへ。
str = euc->GetString(ba);                   // "漢字"

Encoding::Convert()の引数は、変換元Encoding、変換先Encoding、変換対象バイト配列、の3つです。

サロゲートペア

StringやCharはUTF-16なので、サロゲートペアをケアする必要があります。例えばString::Lengthプロパティは、文字列に含まれるCharの数であり、文字数と一致するとは限りません。

サロゲートペアをケアしつつ文字列を解析するために、System::Globalization::StringInfoクラスが提供されています。サロゲートペアを含んだ文字列で試してみましょう。

// U+53F1とU+020B9Fの2文字をUTF-16LEでエンコードしたバイト配列。
array<Byte>^ ba = { 0xf1, 0x53, 0x42, 0xd8, 0x9f, 0xdf };

// Stringへ変換。
Encoding^ utf16le = Encoding::Unicode;
String^ str = utf16le->GetString(ba);

// 3個のCharから成る。
Console::WriteLine(str->Length);                 // 3
if ( !Char::IsSurrogate(str[0]) ) Console::WriteLine("RIGHT");   // RIGHT
if ( Char::IsSurrogate(str[1]) ) Console::WriteLine("RIGHT");    // RIGHT
if ( Char::IsLowSurrogate(str[2]) ) Console::WriteLine("RIGHT"); // RIGHT

// StringInfoで解析すると、文字数は2。
StringInfo^ si = gcnew StringInfo(str);
Console::WriteLine(si->LengthInTextElements);    // 2

// 0番目と1番目の文字を取り出す。
Console::WriteLine(StringInfo::GetNextTextElement(str, 0)->Length);  // 1
Console::WriteLine(StringInfo::GetNextTextElement(str, 1)->Length);  // 2

うーん、最も基本的な情報である文字列を、こんな複雑な仕組みで管理する地球人。宇宙人が見たら笑うでしょうね。

Last modified:2012/05/09 11:47:47
Keyword(s):
References:[.NETアプリ開発] [Unicodeの基礎知識とJavaでの扱い]
This page is frozen.