Unicode CFString:字符串中非代码点的字符计数

Unicode CFString:字符串中非代码点的字符计数,unicode,core-foundation,cfstring,Unicode,Core Foundation,Cfstring,我想知道,有没有办法获取CoreFoundation框架中CFString对象中存储的字符数(由底层Unicode代码点表示) 有可用的函数:CFStringGetLength,但它不做它看起来做的事情 示例:我试图获取包含一个字符(字母“peep of”)的字符串的长度,该字符位于第二个(SMP)Unicode平面中 UInt8 arr[] = {0xf0, 0x90, 0x91, 0x90}; //UTF8 CFStringRef r = CFStringCreateWithBytes(0,

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


有可用的函数:
CFStringGetLength
,但它不做它看起来做的事情

示例:我试图获取包含一个字符(字母“peep of”)的字符串的长度,该字符位于第二个(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中有什么方法可以做到这一点吗?

我找到了一个解决方法。这并不完美,因为它可能需要额外转换到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定义为在单个实体中包含单个代码点。而且,由于实体被定义为4字节大小,并且
CFStringGetBytes
能够获得转换后存储字符串所需的字节数,因此可以通过将字节数除以4来获得代码点的数目


无论如何,
CFStringGetBytes
的主要目的是执行实际转换,因此即使将
nullptr
作为
buffer
参数传递,也可能至少实际发生了转换的主要部分。出于这个原因,如果您想知道用户看到的“字符”的数量,无论是否标准化,都可以使用cfStringGetRangeofComposedCharactersIndex返回的范围循环合成字符序列,并计算迭代次数,那就太好了。

(这是我的猜测)


我找不到有关
CFStringGetLength
返回内容的“无定义”。所有苹果手册都只说UTF-16代码对(?),老实说,我无法理解它的含义。Unicode很复杂,有许多微妙的不同概念。如果没有精确的术语,我们无法找到它是什么

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

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



获取“Unicode Grapheme群集”,最好使用Swift
String
s。Swift
String
有本机接口来访问Grapheme集群。将它们转换为Swift
String
并对其进行迭代。

您是否对字符串进行了规范化?不,据我所知,CoreFoundation没有相应的例程。但是,我没有看到Unicode规范之间的直接联系还有我的问题-你能解释一下你的问题/建议的原因吗?好吧,对于组合字符或分解字符,计数可能不同,特别是在包含这两个字符的字符串中。转换为UTF-32根本不会改变这一点。你仍然需要决定是否需要以及如何进行规范化。我知道规范化可能会改变字符串长度-但这超出了我的问题范围。我不想修改字符串,只需获取给定CFString中存在的代码点的计数。这是正确的答案。在撰写此注释时,CF不会导出任何可以为您执行此操作的符号。此链接为该循环提供了一个片段,用于计数图形:
CFStrinGGETLENGT()
确实返回了“以Unicode代码点表示”的字符数。呈现“@Sean”所需的UTF-16字符序列除了“UTF-16代码对”之外,我找不到任何
CFStringGetLength
返回的定义。我也找不到任何线索“UTF-16代码对”是什么意思。你能解释一下吗“代码对”实际上是“代码点”?