从NSData创建NSString时猜测编码

use*_*444 18 cocoa cocoa-touch nsdata

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

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

HAS*_*HAS 27

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

Objective-C的

+ (NSStringEncoding)stringEncodingForData:(NSData *)data
                          encodingOptions:(NSDictionary *)opts
                          convertedString:(NSString **)string
                      usedLossyConversion:(BOOL *)usedLossyConversion;
Run Code Online (Sandbox Code Playgroud)

迅速

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

现在你可以让框架做出猜测,并且根据我的经验,这非常有效!

从标题(文档目前没有说明方法,但它在WWDC会话204(第270页)中正式提到:

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

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

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

示例(Swift):

var convertedString: NSString?
let encoding = NSString.stringEncoding(for: data, encodingOptions: nil, convertedString: &convertedString, usedLossyConversion: nil)
Run Code Online (Sandbox Code Playgroud)

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


Jen*_*ton 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:]或类似的文件,如果存在,将自动使用.