UTF8 データ列を \uXXXX 形式の Unicode に変換する : Objective-C プログラミング

PROGRAM


UTF8 データ列を \uXXXX 形式の Unicode に変換する

Objective-C で NSData に格納された UTF-8 文字列を、"\uXXXX" という "\u" に続いて 4 桁の Unicode 文字コードに変換してみます。

もっとも、NSString 型が文字列を 2 バイト Unicode で持つようなので、NSString の stringWithData: メソッドを使って NSString 型に変換して characterAtIndex: メソッドで取得した値を使うのが簡単かつ正確な感じなことが後に判って、嬉しいようながっかりなような心地です。

でもせっかく調べてここまで行き着いたのと、他の言語で同じことをしたいときに参考になりそうだったので、記してみることにしました。

 

UTF-8 や Unicode の性質については http://webos-goodies.jp/archives/51072404.html http://ja.wikipedia.org/wiki/UTF-8 辺りが詳しい気がします。また、文字を Unicode の文字コードに変換するとどんな値になるかについては http://pasofaq.jp/development/web/unicode.htm を使って確認できます。

これらの情報から、UTF-8 の 1 文字を構成するバイト列の 2 バイト目以上は必ず、先頭からの 2 ビットが 10 になることと、各バイトのビットの上から 0 が登場したその先に文字コードが入っていることに着目して、Unicode 文字コードを取得するプログラムを作成してみます。

 

厳密にはもっと細かな取り決めに従って、処理を適切に記述しないといけないようにも思えますけど、このような点に着目するだけでもとりあえず、文字コード変換ができるような感じでした。

NSMutableString* result = [[NSMutableString alloc] init];

 

// UTF-8 形式のバイト列を、操作しやすいように const char* 型で取得します。

const char* utf8 = (const char*)data.bytes;

 

// 全文字分の処理を行います。

for (NSUInteger i = 0; i < data.length; i++)

{

char word = *(utf8 + i);

 

// 最初は UTF-8 文字の 1 バイト目であると想定しつつ、頭のビットに 0 が登場する位置を探します。

NSUInteger location = 0;

 

while ((word & 0x80) == 0x80)

{

location++;

word <<= 1;

}

 

// 元の値から頭のフラグを全て落とした値にします。

word >>= location;

 

// 続くバイトデータを考慮しながら、Unicode 1 文字としての文字コードを計算します。

// iOS 5.0 SDK では char は符号付整数のため、マイナスの値をプラスに変換しています。

SInt64 code = (UInt32)(word + (word < 0 ? 256 : 0));

 

while (true)

{

// 次のバイトデータを取得します。末尾の場合は 0 とします。

char next_word = (i+1 < data.length ? *(utf8 + i + 1) : 0);

 

// 2 バイト目のデータであれば、その値を文字コードに反映します。

if ((next_word & 0xC0) == 0x80)

{

// 頭のフラグを除いた値を、文字コードに加えて行きます。

code = code * 0x40 + (next_word & 0x3F);

}

else

{

// 次の文字が UTF-8 での 1 文字目を構成する先頭バイトの場合は、文字コードの計算処理を終了します。

break;

}

 

// 次の文字位置に移動します。

i++;

}

 

// 取得できた文字コードを '\uXXXX' 形式に変換します。

[result appendFormat:@"\\u%04x", code];

}

これで NSMutableString 型の変数 result に、各文字を "\uXXXX" 形式に変換した文字列を取得することが出来ました。

実際には、冒頭で先頭バイトのビット 1 の数を取得しているので、それを元に構成バイト数を判定して、それらの文字コードを取ったりするのが仕様上は適切なのかもしれません。他にも、文字列への変換の際に 16 進数で 5 桁以上のコード値が取得できた場合への配慮なども不足しているような気もします。

それでもとりあえず、このような簡単なプログラムだけでも、UTF-8 を 16 進数 2 バイトの Unicode 表現に変換できる様子なのだから、UTF-8 ってなかなか便利な感じです。

 

ちなみに冒頭でも記載しましたけど、NSString 型は内部的には 2 バイト Unicode で文字列で保持しているため、このような変換プログラムをわざわざ書かなくても簡単に Unicode 文字コードを取得することが可能です。

そのあたりについては 文字列を \uXXXX 形式の Unicode 列に変換する の方に記してみましたので、こちらも参考にしてみてください。

[ もどる ]