好的,所以也许值得在这里单独的答案中指出一些事情。首先,“角色”这个词是有歧义的,所以我们应该根据我们的意思选择一个更合适的术语。 (看字符和字素簇 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/stringsClusters.html在 Apple 开发人员文档以及统一码网站 http://unicode.org了解更多详情。)
如果您要求 UTF-16代码单元,那么你可以使用
unichar ch = [myString characterAtIndex:ndx];
请注意,这是only如果代码点位于基本多语言平面内(即小于 U+FFFF),则相当于 Unicode 代码点。
如果您需要 Unicode代码点,那么您应该知道 UTF-16 支持 BMP 之外的字符(即 U+10000 及以上),使用代理对。这样就会有twoU+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 联盟通常将其称为字素簇以将其与“字符”的其他可能含义区分开)。例子有很多,但最容易理解的可能是组合变音符号。例如,字符“Ä”可以表示为 Unicode 代码点 U+00C4,或一对代码点 U+0041 U+0308。
有时人们(比如@DietrichEpp 在他的答案的评论中)会声称你可以通过在处理字符串之前转换为预组合形式来处理这个问题。这有点转移注意力,因为预组合形式仅处理在 Unicode 中具有预组合等效项的字符。例如它对所有组合标记没有帮助;它对印度语或阿拉伯语脚本没有帮助;它对 Hangul Jamos 没有帮助。还有许多其他案例。
如果你试图操纵字素簇(用户可能认为是“字符”的东西),你可能应该使用 NSString 方法-rangeOfComposedCharacterSequencesForRange:
, rangeOfComposedCharacterSequenceAtIndex:
或 CFString 函数CFStringGetRangeOfComposedCharactersAtIndex
。显然,你不能将字素簇保存在整数变量中,并且它没有固有的数值;相反,它由一串代码点表示,而代码点又由一串代码单元表示。例如:
NSRange gcRange = [myString rangeOfComposedCharacterSequenceAtIndex:ndx];
NSString *graphemeCluster = [myString substringWithRange:gcRange];
注意graphemeCluster
可以是任意长(!)
即便如此,我们仍然忽略了 Unicode 对双向文本的支持等问题的影响。也就是说,NSString 中的代码单元表示的代码点的顺序may在某些情况下,结果可能与您的预期相反。最糟糕的情况涉及嵌入阿拉伯语或希伯来语的英文文本;这is由 Cocoa Text 系统支持,因此您实际上可以在代码中得到双向字符串。
总结一下:一般来说,应该避免检查NSString
and CFString
实例 unichar by unichar。如果可能的话,使用适当的NSString
方法或CFString
函数代替。如果你do如果您正在研究 UTF-16 代码单元,请先熟悉 Unicode 标准(如果您无法阅读 Unicode 书籍本身,我建议您阅读《Unicode 揭秘》),这样您就可以避免重大陷阱。