我正在使用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/