如何检测C字符串能否通过指定编码转换为NSString
编码检测实现方案
针对你的需求,系统没有提供直接的canBeConvertedFromEncoding这类反向检测接口,但有两种成熟的实现方式可以解决问题:
方案1:使用系统原生编码探测API(推荐)
直接用+[NSString stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:]即可实现按优先级尝试编码的需求,这个API就是专门用来从二进制数据中探测匹配编码的。
你可以直接传入你预设的编码优先级列表,API会按顺序尝试匹配,同时输出是否发生了有损转换,刚好可以解决NSMacOSRomanStringEncoding永远不返回失败、只输出乱码的问题:
const char *cString = "你要转换的目标字符串"; NSData *data = [NSData dataWithBytes:cString length:strlen(cString)]; NSString *convertedStr = nil; BOOL lossy = NO; // 按你需要的优先级排列编码数组 NSArray *encodings = @[ @(NSUTF8StringEncoding), @(NSMacOSRomanStringEncoding), @(NSISOLatin1StringEncoding) ]; NSStringEncoding matchedEncoding = [NSString stringEncodingForData:data encodingOptions:@{NSStringEncodingDetectionSuggestedEncodingsKey : encodings, NSStringEncodingDetectionUseOnlySuggestedEncodingsKey : @YES} convertedString:&convertedStr usedLossyConversion:&lossy]; // 如果lossy为YES说明转换有信息损失,大概率是编码不匹配产生乱码,可以根据需求选择是否接受 if (matchedEncoding != 0 && !lossy) { // 拿到正确的convertedStr }
方案2:手动实现反向校验逻辑
如果你需要更灵活的自定义校验规则,可以自己实现编码逐个尝试逻辑,通过反向转换对比解决单字节编码永远返回成功的问题:
- 把
const char*包装为NSData对象 - 按你的优先级顺序尝试用对应编码生成NSString
- 将生成的NSString反向转换为对应编码的NSData,和原数据对比是否完全一致
- 如果不一致说明当前编码不匹配,继续尝试下一个编码
示例代码如下:
const char *cString = "目标字符串"; NSData *rawData = [NSData dataWithBytes:cString length:strlen(cString)]; NSArray *tryEncodings = @[ @(NSUTF8StringEncoding), @(NSMacOSRomanStringEncoding), @(NSISOLatin1StringEncoding) ]; NSString *result = nil; for (NSNumber *encodingNum in tryEncodings) { NSStringEncoding encoding = encodingNum.unsignedIntegerValue; NSString *tempStr = [[NSString alloc] initWithData:rawData encoding:encoding]; if (!tempStr) continue; // 反向转换校验 NSData *convertedBack = [tempStr dataUsingEncoding:encoding allowLossyConversion:NO]; if ([convertedBack isEqualToData:rawData]) { result = tempStr; break; } }
注意要点
- 优先使用系统原生的探测API,准确率和性能都比手动实现更优,还能自动识别BOM头等特殊字符标记
- 不要单独依赖
initWithData:encoding:的返回值判断编码是否匹配,所有单字节编码(比如NSMacOSRoman、NSISOLatin1)几乎不会返回nil,只会生成乱码字符串 - 如果你能接受少量有损转换,可以自行调整校验逻辑中对
usedLossyConversion或者allowLossyConversion的限制
内容的提问来源于stack exchange,提问作者rpatters1
相关产品推荐
相关产品推荐

