如何在Objective-C中将unichar值转换为NSString?

时间:2009-11-21 15:57:21

标签: objective-c unicode nsstring

我有一个存储在unichar变量中的国际字符。此字符不是来自文件或网址。变量本身只存储一个无符号短(0xce91),它是UTF-8格式并转换为希腊大写字母'A'。我试图将该字符放入NSString变量,但我失败了。

我尝试过两种不同的方法:

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];

但这也不起作用。 我显然做了一件非常糟糕的事,但我不知道是什么。 有谁可以帮助我吗 ? 谢谢!

5 个答案:

答案 0 :(得分:54)

unichar greekAlpha = 0x0391;
NSString* s = [NSString stringWithCharacters:&greekAlpha length:1];

现在你可以以任何你喜欢的方式将NSString合并到另一个中。但请注意,现在将希腊字母直接键入NSString文字是合法的。

答案 1 :(得分:21)

由于0xce91采用UTF-8格式且%C期望采用UTF-16,因此上述一种简单的解决方案将无效。要使stringWithFormat:@"%C"正常工作,您需要输入0x391这是UTF-16 unicode。

为了从UTF-8编码的unichar创建一个字符串,你需要首先将unicode拆分成它的八位字节,然后使用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];

答案 2 :(得分:2)

上述答案很好但不考虑长于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];

注意不同的字符串初始化方法,不需要长度参数。

答案 3 :(得分:1)

以下是对单个字符进行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);
}

答案 4 :(得分:1)

上面的代码是道德等同于unichar foo = 'abc';

问题是'Α'没有映射到“执行字符集”中的单个字节(我假设是UTF-8),这是C99§中的“实现定义” 6.4.4.4 10:

  

包含多个字符(例如'ab')或包含未映射到单字节执行字符的字符或转义序列的整数字符常量的值是实现定义的。< / p>

一种方法是使'ab'等于'a'<<8|b。某些Mac / iOS系统标题依赖于OSType / FourCharCode / FourCC之类的内容;脑海中唯一出现的是CoreVideo像素格式。但是,这是不可取的。

如果您真的需要unichar字面值,可以尝试L'A'(技术上它是wchar_t字面值,但在OS X和iOS上,wchar_t通常是UTF- 16因此它适用于BMP内部的事物)。但是,使用@"Α"(只要正确设置源字符编码就可以正常工作)或@"\u0391"(至少从iOS 3 SDK开始工作)就更简单了。