【问题标题】:Guess encoding when creating an NSString from NSData从 NSData 创建 NSString 时猜测编码
【发布时间】:2010-11-23 23:34:38
【问题描述】:

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

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

【问题讨论】:

    标签: cocoa-touch cocoa nsdata


    【解决方案1】:

    在 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. 建议的字符串编码数组(不指定此列表中的第 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 =

    【讨论】:

    • 似乎还没有正式发布是有原因的。我使用 PDF NSData 编码运行它,它返回 -2147482362。
    • 我不太确定它是否打算这样工作。 pdf 不是字符串,此方法从NSData 中查找字符串的编码。你的意图是什么?
    • 我正在通过 SDK 作为 NSData 检索 pdf。我现在只是在 webview 中显示它时遇到问题,因为我不知道编码是什么,甚至是否有编码。
    • 你看过this的回答吗?如果这不起作用,我建议您在 SO 上问您自己的问题,并提供有关您尝试过的内容以及您的代码是什么以及什么不起作用的更多详细信息。 :)
    • 谢谢。我已经修好了。原来我得到的是非 pdf 数据。
    【解决方案2】:

    一般来说,你不能。但是,您可以非常可靠地识别 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:] 或类似名称的文件,则会自动使用它(如果存在)。

    【讨论】:

      猜你喜欢
      • 2014-07-25
      • 1970-01-01
      • 2012-04-13
      • 2017-09-15
      • 2011-01-28
      • 2011-08-31
      • 2011-03-02
      • 1970-01-01
      相关资源
      最近更新 更多