【问题标题】:CFString: Count of characters NOT code points in a stringCFString:字符串中的字符数不是代码点
【发布时间】:2013-03-13 00:19:30
【问题描述】:

我想知道,有什么方法可以获取存储在 CoreFoundation 框架的 CFString 对象中的字符数(由底层 Unicode代码点 表示)。

有可用的功能:CFStringGetLength,但它并没有做它看起来做的事情。

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

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有什么办法吗?

【问题讨论】:

  • CFStringGetLength() 实际上返回“以 Unicode 代码点表示”的字符数。渲染 '????' 所需的 UTF-16 字符序列是 [0xD801,0xDC50]。您似乎要查找的内容(更准确地说)是返回由底层 UTF-16 序列。我将使用正确的 CF API 编写一个示例,该示例很快就能满足您的需求。
  • @Sean 除了“UTF-16 代码对”之外,我找不到任何 CFStringGetLength 返回的定义。而且我找不到任何线索“UTF-16 代码对”是什么意思。你能解释一下“代码对”实际上是“代码点”吗?

标签: unicode core-foundation cfstring


【解决方案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 参数传递,也有可能至少转换的主要部分实际发生了。因此,很高兴听到该问题的另一种解决方案。

【讨论】:

  • 你规范化字符串了吗?
  • 不,据我所知,CoreFoundation 没有这样的例程。但是,我没有看到 Unicode 规范化和我的问题之间的直接联系 - 你能解释你的问题/建议的原因吗?
  • 好吧,组合字符或分解字符的计数可能不同,尤其是在包含两者的字符串中。转换为 UTF-32 根本不会改变这一点。您仍然需要决定是否需要以及如何进行规范化。
  • 我知道规范化可以改变字符串长度——但这超出了我的问题范围。我不想修改字符串,只需获取给定 CFString 中存在的 code points 的计数。
【解决方案2】:

如果您想知道用户看到的“字符”的数量,而不考虑规范化,请使用CFStringGetRangeOfComposedCharactersAtIndex 返回的范围遍历组合的字符序列并计算迭代次数。

【讨论】:

【解决方案3】:

(这是我的猜测...)

我可以找到关于 CFStringGetLength 返回的“没有定义”。所有 Apple 手册都只是说 UTF-16 代码对(?),老实说,我不明白它是什么意思。 Unicode 很复杂,有许多微妙的不同概念。如果没有确切的术语,我们无法找出它是什么。

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

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


要获得“Unicode Grapheme Clusters”,最好使用 Swift Strings。 Swift String 具有访问 Grapheme Clusters 的本机接口。将它们转换为 Swift String 并对其进行迭代。

【讨论】:

    猜你喜欢
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    相关资源
    最近更新 更多