【问题标题】:How to convert a unichar value to an NSString in Objective-C?如何在 Objective-C 中将 unichar 值转换为 NSString?
【发布时间】:2010-12-19 01:14:49
【问题描述】:

我有一个国际字符存储在一个 unichar 变量中。此字符不是来自文件或 url。变量本身只存储一个无符号的 short(0xce91),它是 UTF-8 格式并转换为希腊大写字母“A”。我试图将该字符放入 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];

但这也不起作用。 我显然做错了什么,但我不知道是什么。 有人能帮助我吗 ? 谢谢!

【问题讨论】:

  • 您可以通过按编辑器工具栏中的小按钮 101010 来格式化代码以获得更好的格式。
  • 感谢您告诉我 :)
  • 您确定unichar 是此处使用的正确数据类型吗?以用于 UTF-16 的类型存储 UTF-8 数据是错误的。正如 Jon Jardine 所指出的,有 UTF-8 字符长于 16 位......你也可以使用 NSString 作为单个字符吗(NSString greekAlpha = @"Α" 然后在stringWithFormat 中使用 %@)?
  • 0xce91 实际上是“HANGUL SYLLABLE KAEG”的Unicode,所以我不明白为什么你会期望从中得到一个字母字符。您似乎对 UTF-8 中的 0xc9、0x91 拉丁小写字母 ALPHA 感到困惑。完全不同的编码。 Unicode 值为 0x0251。

标签: objective-c unicode nsstring


【解决方案1】:

上面的代码相当于unichar foo = 'abc';

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

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

一种方法是使'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 开始就可以使用)要简单得多。

【讨论】:

    【解决方案2】:
    unichar greekAlpha = 0x0391;
    NSString* s = [NSString stringWithCharacters:&greekAlpha length:1];
    

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

    【讨论】:

    • 这仅适用于一个角色。不知道为什么这被否决了。 +1
    • 为什么这不是答案?
    • unichar 是一个无符号短...仅 16 位。如果你有像表情符号这样的 32 位 unicode,它将无法工作。例如0x1F347
    • @Billy 提出的问题不是表情符号,而是希腊字母。
    【解决方案3】:

    这里是对单个字符进行 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】:

      上面的答案很好,但没有考虑超过 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];
      

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

      【讨论】:

      • 但是 'unichar' 是 16 位类型,所以 utf8char 不能保存超过 16 位的值。
      【解决方案5】:

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

      【讨论】:

      • 在仔细查看我发布的链接后,我也意识到了这一点。我用这些信息和您的问题的解决方案更新了我的答案。
      • 谢谢。这正是我想要的!所以,我的比特被打乱了:)。尽管我是这个网站的新成员,但我已经使用它很长一段时间了(主要是 c# 的东西,只是用 Objective-c 弄湿了我的脚)而且我发现有些人会走多远令人惊讶帮助别人。再次感谢您! :)
      • @Terry - StackOverflow 是程序员懒惰规则的反例。奇怪的是,99% 的 Linux 从未经过代码审查,但几乎所有关于 SO 的问题、答案和评论都经过审查、编辑、投票和讨论。 SO 的特性已经在 MetaStackOverflow 上实现了。
      猜你喜欢
      • 2018-04-27
      • 2018-04-06
      • 2011-09-19
      • 2014-10-25
      • 2011-09-18
      • 2020-10-26
      • 2016-12-17
      • 2010-12-22
      • 2012-10-06
      相关资源
      最近更新 更多