web-dev-qa-db-ja.com

Objective-Cでunichar値をNSStringに変換する方法は?

Unichar変数に格納されている国際文字を持っています。この文字はファイルまたはURLからのものではありません。変数自体は、UTF-8形式であり、ギリシャ大文字の「A」に変換される符号なしshort(0xce91)のみを格納します。その文字をNSString変数に入れようとしていますが、惨めに失敗します。

私は2つの異なる方法を試しましたが、どちらも失敗しました:

unichar greekAlpha = 0xce91; //could have written greekAlpha = 'Α' instead.

NSString *theString = [NSString stringWithFormat:@"Greek Alpha: %C", greekAlpha];

駄目だ。変な漢字が出ます。余談ですが、これは英語の文字で完全に機能します。

それから私もこれを試しました:

NSString *byteString = [[NSString alloc] initWithBytes:&greekAlpha
                                                length:sizeof(unichar)
                                              encoding:NSUTF8StringEncoding];

しかし、これも機能しません。私は明らかにひどく悪いことをしていますが、何が原因なのかわかりません。誰かが私を助けてくれますか?ありがとう!

31
Terry

0xce91はUTF-8形式であり、%CはUTF-16であると想定しているため、上記のような単純なソリューションは機能しません。 stringWithFormat:@"%C"が機能するためには、UTF-16ユニコードである0x391を入力する必要があります。

UTF-8でエンコードされたunicharから文字列を作成するには、まずユニコードをオクテットに分割してから、initWithBytes:length:encodingを使用する必要があります。

unichar utf8char = 0xce91; 
char chars[2];
int len = 1;

if (utf8char > 127) {
    chars[0] = (utf8char >> 8) & (1 << 8) - 1;
    chars[1] = utf8char & (1 << 8) - 1; 
    len = 2;
} else {
    chars[0] = utf8char;
}

NSString *string = [[NSString alloc] initWithBytes:chars
                                            length:len 
                                          encoding:NSUTF8StringEncoding];
21
hallski
unichar greekAlpha = 0x0391;
NSString* s = [NSString stringWithCharacters:&greekAlpha length:1];

そして今、あなたはあなたが好きな方法でそのNSStringを別のものに組み込むことができます。ただし、ギリシャ文字のアルファをNSStringリテラルに直接入力することは現在は合法であることに注意してください。

55
matt

上記の答えは素晴らしいですが、16ビットより長いUTF-8文字は考慮されていません。省略記号-0xE2,0x80,0xA6。これがコードの微調整です:

if (utf8char > 65535) {
   chars[0] = (utf8char >> 16) & 255;
   chars[1] = (utf8char >> 8) & 255;
   chars[2] = utf8char & 255; 
   chars[3] = 0x00;
} else if (utf8char > 127) {
    chars[0] = (utf8char >> 8) & 255;
    chars[1] = utf8char & 255; 
    chars[2] = 0x00;
} else {
    chars[0] = utf8char;
    chars[1] = 0x00;
}
NSString *string = [[[NSString alloc] initWithUTF8String:chars] autorelease];

長さパラメーターを必要としない別の文字列初期化メソッドに注意してください。

2
Jon Jardine

以下は、単一文字のUTF-8エンコードのアルゴリズムです。

if (utf8char<0x80){ 
    chars[0] = (utf8char>>0)  & (0x7F | 0x00);
    chars[1] = 0x00;
    chars[2] = 0x00;
    chars[3] = 0x00;
}
else if (utf8char<0x0800){
    chars[0] = (utf8char>>6)  & (0x1F | 0xC0);
    chars[1] = (utf8char>>0)  & (0x3F | 0x80);
    chars[2] = 0x00;
    chars[3] = 0x00;
}
else if (utf8char<0x010000) {
    chars[0] = (utf8char>>12) & (0x0F | 0xE0);
    chars[1] = (utf8char>>6)  & (0x3F | 0x80);
    chars[2] = (utf8char>>0)  & (0x3F | 0x80);
    chars[3] = 0x00;
}
else if (utf8char<0x110000) {
    chars[0] = (utf8char>>18) & (0x07 | 0xF0);
    chars[1] = (utf8char>>12) & (0x3F | 0x80);
    chars[2] = (utf8char>>6)  & (0x3F | 0x80);
    chars[3] = (utf8char>>0)  & (0x3F | 0x80);
}
1
yusufag

上記のコードは、unichar foo = 'abc';の道徳的同等物です。

問題は、'Α'が、 C99 §6.4.4.410:

複数の文字('ab'など)を含む整数文字定数の値、または1バイトの実行文字にマップされない文字またはエスケープシーケンスを含む値は、実装定義です。

1つの方法は、'ab''a'<<8|bと等しくすることです。一部のMac/iOSシステムヘッダーは、OSType/FourCharCode / FourCC ;のようにこれに依存しています。頭に浮かぶのは、iOSで唯一CoreVideoピクセル形式です。ただし、これは移植性がありません。

unicharリテラルが本当に必要な場合は、L'A'を試すことができます(技術的にはwchar_tリテラルですが、OS XとiOSではwchar_tは通常UTF-16なので、 BMP内で機能します)。ただし、@"Α"(ソースの文字エンコーディングを正しく設定している限り機能します)または@"\u0391"(少なくともiOS 3 SDK以降で機能します)を使用する方がはるかに簡単です。

1
tc.