从NSData创建NSString时猜测编码

时间:2009-08-29 11:01:03

标签: cocoa-touch cocoa nsdata

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

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

2 个答案:

答案 0 :(得分:26)

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

<强>目标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 (page 270)中正式提到:

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

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

         

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

示例(Swift):

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

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

答案 1 :(得分: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:]或类似文件打开文件,则会自动使用此文件。