由于历史原因,Cocoa的Unicode实现是16位:它通过“代理对”处理0xFFFF
以上的Unicode字符。这意味着以下代码无效:
NSString myString = @"";
uint32_t codepoint = [myString characterAtIndex:0];
printf("%04x\n", 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("%04x\n", codepoint); // prints "20d20"
使用mbtowc
的这个代码有效,但它仍然非常冗长,影响全局状态,不是线程安全的,并且可能会填充自动释放池:
setlocale(LC_CTYPE, "UTF-8");
wchar_t codepoint;
mbtowc(&codepoint, [@"" UTF8String], 16);
printf("%04x\n", codepoint); // prints "20d20"
是否有任何简单的 Cocoa / Foundation习惯用法从NSString中提取第一个(或第N个)Unicode代码点?最好是只返回码点的单行?
this otherwise excellent summary of Cocoa Unicode support中给出的答案(接近文章末尾)只是“不要尝试。如果你的输入包含代理对,过滤掉它们或其他东西,因为没有理智的方法来处理它们适当“。
答案 0 :(得分:4)
单个Unicode代码点可能是代理项对,但并非所有语言字符都是单个代码点。即并非所有语言字符都由一个或两个UTF-16单位表示。许多字符由一系列Unicode代码点表示。
这意味着除非您正在处理Ascii,否则您必须将语言字符视为子字符串,而不是索引处的unicode代码点。
获取索引0处字符的子字符串:
NSRange r = [[myString rangeOfComposedCharacterSequenceAtIndex:0];
[myString substringWithRange:r];
根据您实际希望做的事情,这可能是您想要的,也可能不是。例如虽然这会给你'字符边界',但这些不会对应于特定于语言的光标插入点。