4

由于历史原因,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 代码点?最好是只返回代码点的单行代码?

在这篇关于 Cocoa Unicode 支持的出色总结(接近文章末尾)中给出的答案只是“不要尝试。如果您的输入包含代理对,请将它们过滤掉或其他什么,因为没有理智的方法来处理它们适当地。”

4

1 回答 1

5

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

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

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

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

这可能是也可能不是您想要的,这取决于您实际希望做什么。例如,尽管这会给您“字符边界”,但它们不会对应于特定于语言的光标插入点。

于 2012-10-08T23:11:54.797 回答