如何发现 c 字符串是否可以使用给定编码编码为 NSString



我正在尝试实现将const char *转换为NSString的代码。我想按指定的顺序尝试多种编码,直到找到一种有效的编码。不幸的是,NSString上的所有initWith...方法都说,如果编码不起作用,结果是未定义的。

特别是,(有时)我想首先尝试编码为似乎永远不会失败的NSMacOSRomanStringEncoding。相反,它只是编码gobbledygook。我可以提前执行某种检查吗?(喜欢canBeConvertedToEncoding但在另一个方向?

与其尝试一个接一个地编码,直到找到匹配项,不如考虑让NSString在这里使用+[NSString stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:]来帮助你,给定字符串数据和一些选项,它可能能够为你检测编码,并返回它(以及实际解码的字符串)。

特别是对于您的用例,由于您有一个想要尝试的编码列表,因此encodingOptions参数将允许您使用NSStringEncodingDetectionSuggestedEncodingsKey传递这些编码。

因此,给定一个 C 字符串和一些可能的编码选项,您可以执行以下操作:

NSString *decodeCString(const char *source, NSArray<NSNumber *> *encodings) {
NSData * const cStringData = [NSData dataWithBytesNoCopy:(void *)source length:strlen(source) freeWhenDone:NO];

NSString *result = nil;
BOOL usedLossyConversion = NO;
NSStringEncoding determinedEncoding = [NSString stringEncodingForData:cStringData
encodingOptions:@{NSStringEncodingDetectionSuggestedEncodingsKey: encodings,
      NSStringEncodingDetectionUseOnlySuggestedEncodingsKey: @YES}
convertedString:&result
usedLossyConversion:&usedLossyConversion];

/* Decide whether to do anything with `usedLossyConversion` and `determinedEncoding. */
return result;
}

用法示例:

NSString *result = decodeCString("Hello, world!", @[@(NSShiftJISStringEncoding), @(NSMacOSRomanStringEncoding), @(NSASCIIStringEncoding)]);
NSLog(@"%@", result); // => "Hello, world!"

如果您不是 100% 关心使用要尝试的编码列表,则可以删除NSStringEncodingDetectionUseOnlySuggestedEncodingsKey选项。


关于您传入的编码数组需要注意的一件事:尽管文档不承诺按顺序尝试建议的编码,但通过(当前)方法实现的反汇编表明数组是使用快速枚举(即按顺序)枚举的。我可以想象这在未来可能会改变(或者过去有所不同),所以如果这对你来说是一个硬性要求,理论上你可以通过一次重复调用一个编码来解决这个问题+stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:但考虑到这种方法的复杂性,这可能会非常昂贵。

相关内容

最新更新