目标c中unicode字符的数值

时间:2011-11-14 02:22:03

标签: objective-c cocoa unicode

是否可以从objective-c中的unicode字符获取数值?

@“A”是0041,@“➜”是279C,@“Ω”是03A9,@“झ”是091D ......?

2 个答案:

答案 0 :(得分:6)

好的,所以也许值得在这里单独回答一些问题。首先,“字符”一词含糊不清,所以我们应该根据我们的意思选择一个更合适的术语。 (有关详细信息,请参阅Apple开发人员文档中的Characters and Grapheme Clusters以及Unicode website。)

如果您要求使用UTF-16 代码单元 ,则可以使用

unichar ch = [myString characterAtIndex:ndx];

请注意,在代码点位于基本多语言平面内(即小于U + FFFF)的情况下,等同于Unicode代码点。

如果您要求使用Unicode 代码点 ,那么您应该知道UTF-16支持BMP之外的字符(即U + 10000及以上)使用代理对。因此,对于U + 10000以上的任何代码点,将有两个 UTF-16代码单元。要检测这种情况,您需要执行类似

的操作
uint32_t codepoint = [myString characterAtIndex:ndx];

if ((codepoint & 0xfc00) == 0xd800) {
  unichar ch2 = [myString characterAtIndex:ndx + 1];

  codepoint = (((codepoint & 0x3ff) << 10) | (ch2 & 0x3ff)) + 0x10000;
}

请注意,在生产代码中,您还应该测试和处理代理对以某种方式被截断的情况。

重要,UTF-16代码单元和Unicode代码点都不一定对应于最终用户认为是“字符”的任何内容(Unicode联盟通常将此称为< em> grapheme cluster 以区别于“character”的其他可能含义。有很多例子,但最简单的理解可能是结合变音符号。例如,字符'Ä'可以表示为Unicode代码点U + 00C4,或者表示为一对代码点,U + 0041 U + 0308。

有时人们(比如@DietrichEpp在他的回答评论中)声称你可以通过在处理你的字符串之前转换为预先组合的形式来解决这个问题。这是一个红色鲱鱼,因为预组合形式只处理在Unicode中具有预组合等效的字符。例如它无助于所有组合标记;它对印度语或阿拉伯语脚本没有帮助;它对Hangul Jamos没有帮助。还有很多其他案例。

如果您正在尝试操作字形集群 (用户可能认为是“字符”的东西),您应该使用NSString方法{{1 },-rangeOfComposedCharacterSequencesForRange:或CFString函数rangeOfComposedCharacterSequenceAtIndex:。显然你不能在一个整数变量中保存一个字形簇,它没有固有的数值;相反,它由一串代码点表示,代码点由一串代码单元表示。例如:

CFStringGetRangeOfComposedCharactersAtIndex

请注意,NSRange gcRange = [myString rangeOfComposedCharacterSequenceAtIndex:ndx]; NSString *graphemeCluster = [myString substringWithRange:gcRange]; 可能是任意长的(!)

即便如此,我们也忽略了Unicode对双向文本支持等问题的影响。也就是说,NSString 中代码单元所代表的代码点的顺序可能在某些情况下与您的预期相反。更糟糕的案件涉及嵌入阿拉伯语或希伯来语的英文文本; Cocoa Text系统支持 ,因此您最终可以在代码中使用双向字符串。

总结一下:一般来说,应该避免通过unichar检查graphemeClusterNSString实例unichar 。如果可能,请使用适当的CFString方法或NSString函数。如果您发现自己正在检查UTF-16代码单元,请首先熟悉Unicode标准(如果您无法通过Unicode本书阅读,我推荐“Unicode Demystified”),所以你可以避免重大陷阱。

答案 1 :(得分:2)

Cocoa字符串允许您使用-characterAtIndex:访问UTF-16元素,因此以下代码将字符串转换为unicode代码点:

unsigned strToChar(NSString *str)
{
    unsigned c1, c2;
    c1 = [str characterAtIndex:0];
    if ((c1 & 0xfc00) == 0xd800) {
        c2 = [str characterAtIndex:1];
        return (((c1 & 0x3ff) << 10) | (c2 & 0x3ff)) + 0x10000;
    } else {
        return c1;
    }
}

我不知道有任何便利功能。当有人使用BMP之外的字符时,你可以使用-characterAtIndex:单独使用你的代码。 OS X上的许多应用程序都以这种方式破坏了。

下面应该呈现为音乐剧“G谱号”,U + 1D11E,但是如果你将它复制并粘贴到一些文本编辑器(TextMate)中,它们会让你做一些奇怪的事情,如删除一半的角色,at你的文本文件是垃圾。