提取NSString的第一个Unicode代码点的最简单方法(在BMP之外)?

时间:2012-10-08 20:05:41

标签: cocoa nsstring surrogate-pairs

由于历史原因,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中给出的答案(接近文章末尾)只是“不要尝试。如果你的输入包含代理对,过滤掉它们或其他东西,因为没有理智的方法来处理它们适当“。

1 个答案:

答案 0 :(得分:4)

单个Unicode代码点可能是代理项对,但并非所有语言字符都是单个代码点。即并非所有语言字符都由一个或两个UTF-16单位表示。许多字符由一系列Unicode代码点表示。

这意味着除非您正在处理Ascii,否则您必须将语言字符视为子字符串,而不是索引处的unicode代码点。

获取索引0处字符的子字符串:

NSRange r = [[myString rangeOfComposedCharacterSequenceAtIndex:0];
[myString substringWithRange:r];

根据您实际希望做的事情,这可能是您想要的,也可能不是。例如虽然这会给你'字符边界',但这些不会对应于特定于语言的光标插入点。