好的,所以也许值得在这里单独回答一些问题.首先,"字符"一词含糊不清,所以我们应该根据我们的意思选择一个更合适的术语.(有关详细信息,请参阅Apple开发人员文档中的字符和字形群集以及Unicode网站.)
如果您要求UTF-16 代码单元,那么您可以使用
unichar ch = [myString characterAtIndex:ndx];
Run Code Online (Sandbox Code Playgroud)
请注意,在代码点位于Basic Multilingual Plane(即小于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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,在生产代码中,您还应该测试和处理代理对以某种方式被截断的情况.
重要的是,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];
Run Code Online (Sandbox Code Playgroud)
注意,graphemeCluster可能是任意长的(!)
即便如此,我们也忽略了Unicode对双向文本支持等问题的影响.也就是说,通过在的NSString代码单位表示的代码点的顺序可以在某些情况下,你可能期望相反.更糟糕的案件涉及嵌入阿拉伯语或希伯来语的英文文本; 这是由Cocoa Text系统支持的,因此您最终可以在代码中使用双向字符串.
总结一下:一般来说,应该避免通过unichar 检查NSString和CFString实例unichar.如果可能,请使用适当的NSString方法或CFString功能.如果您确实发现自己正在检查UTF-16代码单元,请首先熟悉Unicode标准(如果您不能阅读Unicode本书,我建议使用"Unicode Demystified"),以便您可以避免主要陷阱.
| 归档时间: |
|
| 查看次数: |
1781 次 |
| 最近记录: |