CFString:字符数不是字符串中的代码点

时间:2013-03-23 01:16:22

标签: unicode core-foundation cfstring

我想知道,有没有办法获得存储在CoreFoundation框架中的CFString对象中的字符数(由底层Unicode 代码点表示)。

有可用的功能:CFStringGetLength,但它不会做它似乎做的事情。

示例:我正在尝试获取包含一个字符(Shavian Alphabet的字母“peep”)的字符串的长度,该字符位于第二个(SMP)Unicode平面中。

UInt8 arr[] = {0xf0, 0x90, 0x91, 0x90}; //UTF8
CFStringRef r = CFStringCreateWithBytes(0, arr, sizeof(arr),
                                        kCFStringEncodingUTF8, false);
CFIndex length = CFStringGetLength(r);

文档说明它返回:

  

存储在字符串中的字符数(以UTF-16代码对表示。

正如您所看到的,这句话是矛盾的 - 字符数并不总是等于UTF-16代码点的数量。但是,括号中的部分更准确 - 函数的实际结果是UTF-16序列的数量。在我的例子中,函数的结果是 2 (以UTF-16编码字符所需的序列的长度),而函数名称表明结果将是 1 在我看来)。

我想找到一种方法来获取Unicode代码点的字符数。有没有办法在CoreFoundation中做到这一点?

3 个答案:

答案 0 :(得分:1)

我找到了解决方法。这并不完美,因为它可能需要额外转换为UTF-32。

UInt8 arr[] = {0xf0, 0x90, 0x91, 0x90}; //UTF8, 
CFStringRef r = CFStringCreateWithBytes(0,
                                        arr,
                                        sizeof(arr),
                                        kCFStringEncodingUTF8,
                                        false);
CFIndex length = CFStringGetLength(r);
CFRange range = CFRangeMake(0, length);
CFIndex bytes;
CFStringGetBytes(r, range, kCFStringEncodingUTF32, 0, false, nullptr,
                 0, &bytes);
CFIndex characterCount = bytes/4;

变通方法利用事实,与UTF-16相比,UTF-32 按照定义在单个实体中包含单个代码点。并且,由于实体被定义为四个字节大小,并且CFStringGetBytes能够获得转换后存储字符串所需的字节数,因此可以通过将字节数除以4来获得代码点数。

无论如何,CFStringGetBytes主要目的是执行实际转换,因此即使将nullptr作为buffer参数传递,也可能至少实际发生转换的主要部分。因此,听到问题的另一种解决方案会很棒。

答案 1 :(得分:1)

如果您想知道用户看到的“字符”数量,无论规范化如何,都可以使用CFStringGetRangeOfComposedCharactersAtIndex返回的范围循环组合字符序列并计算迭代次数。

答案 2 :(得分:0)

(这是我的猜测 ...)

我发现CFStringGetLength返回的内容“没有定义”。 Apple的所有手册都只说 UTF-16代码对(?),说实话,我不知道这是什么意思。 Unicode很复杂,并且有许多微妙的不同概念。没有精确的术语,我们无法找到它。

无论如何,我认为[NSString length]CFString应该是相同的,因为NSString[NSString length]是免费的桥接,并且它们应该存储相同的数据以提供最佳性能。并且NSString返回 UTF-16代码单元的编号。这在Apple手册中有严格定义。请注意条款差异。 “代码单元”是定义明确的Unicode术语,但是“代码对”是未知的。 (有人知道吗?)“代码单位”与“代码点”也不相同。

因此,我假设它会返回“ UTF-16代码单元”,但我不会打赌。我会将其转换为[NSString length]并调用String以获取严格定义的数字。


要获取“ Unicode音素簇”,最好使用Swift String。 Swift String具有访问Grapheme群集的本机界面。将它们转换为Swift 2019-10-26并对其进行迭代。