19

NSString从我可以使用的文件中读取时initWithContentsOfFile:usedEncoding:error:,它会猜测文件的编码。

当我创建它时,NSData我唯一的选择是initWithData:encoding:我必须显式传递编码。NSData当我使用而不是文件时,如何可靠地猜测编码?

4

2 回答 2

30

在 iOS 8 和 OS X 10.10 中有一个新的 API NSString

Objective-C

+ (NSStringEncoding)stringEncodingForData:(NSData *)data
                          encodingOptions:(NSDictionary *)opts
                          convertedString:(NSString **)string
                      usedLossyConversion:(BOOL *)usedLossyConversion;

迅速

open class func stringEncoding(for data: Data,
                   encodingOptions opts: [StringEncodingDetectionOptionsKey : Any]? = nil, 
                 convertedString string: AutoreleasingUnsafeMutablePointer<NSString?>?, 
                    usedLossyConversion: UnsafeMutablePointer<ObjCBool>?) -> UInt

现在您可以让框架进行猜测,并且根据我的经验,效果非常好!

从标题(文档目前没有说明该方法,但在WWDC Session 204(第 270 页)中正式提及)

  1. 建议的字符串编码数组(不指定此列表中的第 3 个选项,所有字符串编码都会被考虑,但数组中的编码优先级更高;此外,数组中编码的顺序很重要:第一个编码有比数组中的第二个更高的偏好)
  2. 不使用的字符串编码数组(根本不会考虑此列表中的字符串编码)
  3. 一个布尔选项,指示是否只考虑建议的字符串编码
  4. 一个布尔选项,指示是否允许有损
  5. 为神秘字节提供特定字符串替代的选项
  6. 当前用户的语言
  7. 一个布尔选项,指示数据是否由 Windows 生成

如果字典中的值类型错误(例如 NSStringEncodingDetectionSuggestedEncodingsKey 的值不是数组),则会抛出异常。

如果字典中的值未知(例如,建议的字符串编码数组中的值不是有效的编码),这些值将被忽略。

示例(斯威夫特):

var convertedString: NSString?
let encoding = NSString.stringEncoding(for: data, encodingOptions: nil, convertedString: &convertedString, usedLossyConversion: nil)

如果您只想要解码的字符串而不关心编码,您可以删除let encoding =

于 2014-11-04T16:53:25.180 回答
12

一般来说,你不能。但是,您可以非常可靠地识别 UTF-8 文件——如果一个文件是有效的 UTF-8,那么它不太可能是任何其他编码(除非所有字节都在 ASCII 范围内,在这种情况下任何“扩展的 ASCII” 编码,包括 UTF-8,会给你同样的结果)。所有 Unicode 编码还有一个可选的BOM来标识它们。所以一个合理的方法是:

  • 寻找有效的 BOM。如果有,请使用适当的编码。
  • 否则,尝试将其解释为 UTF-8。您可以通过调用initWithData:data encoding:NSUTF8StringEncoding并检查结果是否为非零来做到这一点。
  • 如果失败,请使用默认的 8 位编码,例如-[NSString defaultCStringEncoding](提供适合区域设置的猜测)。

可以通过尝试各种不同的编码并选择中间有垃圾的字母序列最少的编码来改进最后一步的猜测,其中“垃圾”是任何不是字母、空格或普通标点符号的字符标记。这将显着增加复杂性,但实际上并不可靠。

简而言之,为了能够处理所有可用的编码,您需要执行 TextEdit 所做的事情:将决定权交给用户。

哦,还有一件事:从 10.5 开始,编码通常与文件一起存储在未记录的 com.apple.TextEncoding 扩展属性中。如果您打开带有+[NSString stringWithContentsOfFile:]或类似的文件,如果存在,它将自动使用。

于 2009-08-29T15:55:00.010 回答