由于历史原因,Cocoa的Unicode实现是16位的:它通过"代理对"处理0xFFFF
以上的Unicode字符。这意味着以下代码将不起作用:
NSString myString = @"𠬠";
uint32_t codepoint = [myString characterAtIndex:0];
printf("%04xn", codepoint); // incorrectly prints "d842"
现在,这段代码在 100% 的时间内有效,但它非常冗长:
NSString myString = @"𠬠";
uint32_t codepoint;
[@"𠬠" getBytes:&codepoint maxLength:4 usedLength:nil
encoding:NSUTF32StringEncoding options:0
range:NSMakeRange(0,2) remainingRange:nil];
printf("%04xn", codepoint); // prints "20d20"
这个使用 mbtowc
的代码是有效的,但它仍然非常冗长,影响全局状态,不是线程安全的,并且可能会填满自动发布池:
setlocale(LC_CTYPE, "UTF-8");
wchar_t codepoint;
mbtowc(&codepoint, [@"𠬠" UTF8String], 16);
printf("%04xn", codepoint); // prints "20d20"
是否有任何简单的Cocoa/Foundation习惯用法用于从NSString中提取第一个(或N个)Unicode代码点?最好是只返回代码点的单行代码?
在这个关于Cocoa Unicode支持的优秀总结(接近文章末尾)中给出的答案只是"不要尝试它。如果你的输入包含代理对,请过滤掉它们或其他东西,因为没有理智的方法可以正确处理它们。
单个 Unicode 代码点可能是代理项对,但并非所有语言字符都是单个代码点。 即并非所有语言字符都由一个或两个 UTF-16 单元表示。许多字符由一系列 Unicode 码位表示。
这意味着,除非你正在处理 Ascii,否则你必须将语言字符视为子字符串,而不是索引处的 unicode 代码点。
获取索引 0 处字符的子字符串:
NSRange r = [[myString rangeOfComposedCharacterSequenceAtIndex:0];
[myString substringWithRange:r];
这可能是你想要的,也可能不是你想要的,这取决于你实际希望做什么。 例如,虽然这会给你"字符边界",但这些不会对应于特定于语言的光标插入点。