我正在使用CFStringTokenizer将大量的文本分解成单词,但是我很难桥接CFString正在使用的编码和UTF8。考虑一下:

NSString *theString = @"Lorem ipsum dolor sit amet!";

const char *theCString = [theString cStringUsingEncoding:NSUTF8StringEncoding];

tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault,
                                    (__bridge CFStringRef)theString,
                                    CFRangeMake(0, [theString length]),
                                    kCFStringTokenizerUnitWordBoundary,
                                    locale);

while ((tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer)) != kCFStringTokenizerTokenNone) {
    tokenRange = CFStringTokenizerGetCurrentTokenRange(tokenizer);
    memcpy(resultPtr, theCString+tokenRange.location, tokenRange.length);
}


不幸的是,如果遇到任何非ASCII字符,则在尝试从C字符串读取时,令牌生成器报告的范围不正确。我该如何从令牌生成器获取正确的范围,以便能够从我的C字符串中提取正确的字符?

需要澄清的是,memcpy的东西比上面的要复杂得多,并且对于在我的目标设备iPhone上的性能是必需的。因此,我什至无法执行创建CFString子字符串并将其转换的操作,我需要C字符串中的范围。有什么方法可以做到,而无需重新实现各种单词边界库,使其在我需要使用的各种不同语言环境下都能正常工作? (这是尽可能多的,所以我不能只是通过寻找''来进行迭代。)

亚历克

最佳答案

NSString和CFString处理UTF-16,而不是UTF-8,但这不是真正的问题。

您的代码有两个问题:


您假设C字符串的索引与源字符串的索引相对应。
您正在一次将整个字符串复制并转换为UTF-8 C字符串。


#1是范围不匹配的原因,而#2则可能导致较高的内存使用量,具体取决于字符串的长度和内容。 (UTF-8在某些字母表中每个字符最多可以占用四个字节,然后为C字符串终止符添加一个。)

您可以一次更改即可解决这两个问题。

创建一个NSMutableData来保存输出。对于每个令牌,将数据长度设置为范围的length;然后,告诉字符串以所需的编码获取所需范围内的字节,并将其存储在数据的mutableBytes缓冲区中。 NSString具有a method with a very long selector(简称为getBytes:::::::),您将要使用它。

由于您仅将与字符串相对的范围与字符串一起使用,因此不会出现索引/范围不匹配的情况,并且将正确输出每个标记。

如果确实需要C字符串,则可以将数据的长度设置为范围的length + 1,然后在获取令牌字节之后,使用单独的分配将最后一个字节设置为'\0'。 (如果没有单独的分配,则该字节可以保存先前的值。)

关于ios - CFStringTokenizer在UTF8 C字符串中的 token 范围,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8662691/

10-09 16:14
查看更多