2009-08-29 37 views
15

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

当我从NSData创建它时,尽管我唯一的选择是initWithData:encoding:,我必须明确地通过编码。当我使用NSData而不是文件时,如何可靠地猜出编码?

回答

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:]或类似文件打开文件,则会自动使用该文件(如果存在)。

23

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

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

  1. 建议串编码的阵列(没有指定此列表中的第三选项,所有字符串编码都会被考虑,但阵列中的编码将具有更高的优先级;此外,阵列中编码的顺序很重要:第一个编码比第二个编码具有更高的优先级)
  2. 数组字符串编码不能使用(这个列表中的字符串编码不会是c onsidered在所有)
  3. 仅指示所建议的字符串编码是否被视为
  4. 指示有损是否允许一个布尔选项布尔选项
  5. ,给出了一个特定的字符串可分别代替用于神秘的选项字节
  6. 当前用户的语言
  7. 布尔选项指示是否是由Windows

产生的数据。如果在字典中的值有错误的类型(例如,NSS的价值tringEncodingDetectionSuggestedEncodingsKey不是数组),抛出异常。

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

例(SWIFT):

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

如果你只是想解码串并不在乎编码,您可以删除let encoding =

+0

好像有就是为什么它是有原因的尚未官方。我用它的PDF NSData编码运行它返回-2147482362。 – FireDragonMule

+0

我不太确定这是否如此。 pdf不是一个字符串,并且此方法从“NSData”中查找字符串的编码。你的意图是什么? – HAS

+0

我正在通过SDK以NSData格式检索pdf。我只是在webview中显示问题,因为我不知道编码是什么,甚至是编码。 – FireDragonMule