来自文本文件的 NSString 编码未知

问题描述 投票:0回答:3

我正在尝试根据Apple的文档显示未知编码的文本文件的内容:

尝试 stringWithContentsOfFile:usedEncoding:error: 或 initWithContentsOfFile:usedEncoding:error: (或基于 URL 的等效项)。这些方法尝试确定资源的编码,如果成功则通过引用返回所使用的编码。

如果(1)失败,请尝试通过指定UTF-8作为编码来读取资源。

如果 (2) 失败,请尝试适当的旧编码。这里的“适当”有点取决于具体情况;它可能是默认的 C 字符串编码,也可能是 ISO 或 Windows Latin 1 或其他编码,具体取决于您的数据来自何处。

这并不总是有效。有更可靠的方法来检测编码吗?

iphone ios encoding utf-8 nsstring
3个回答
1
投票

您应该使用可以检测编码的 NSAttributedString。经过长时间测试不同的解决方案,我使用它:

NSError *error;
NSDictionary *options = [NSDictionary dictionary];
NSDictionary *attributes;
NSAttributedString *theString = [[NSAttributedString alloc] initWithURL:fileURL options:options documentAttributes:&attributes error:&error];
NSInteger detectedEncoding = [[attributes objectForKey:@"CharacterEncoding"] integerValue];

我测试了来自许多来源/环境的许多文件,它似乎很有效(因此你应该检查

error
是否是
nil
)。对于从 Excel 导出的纯 csv 文件,我得到这个属性字典(30 个值意味着
NSMacOSRomanStringEncoding
:

{
    CharacterEncoding = 30;
    DocumentType = NSPlainText;
    UTI = "public.plain-text";
}

0
投票

如果您提前不知道数据的编码,则必须通过分析原始数据来猜测,这有时会导致错误的猜测,从而导致解码不可靠。如有疑问,只需询问用户要使用哪种编码。


0
投票

这是 Swift 的答案(可能与 10 年前不相关)。 我尝试使用 Swift 自己提交这样的问题,当 Stack Overflow 询问我的问题是否重复时,我遇到了这个非常古老的线程。其实丹尼斯的回答还是可以的。

我正在努力

string = try String(contentsOf: url, encoding: .utf8)

但它只是返回一条错误消息,例如:文件...无法使用文本编码“Unicode (UTF-8)”打开,并且字符串保持为空。所以 Denis 在 Swift 中的回答是这样的:

// Open the file independently of its encoding!
var options: [NSAttributedString.DocumentReadingOptionKey : Any] = [:]
var dict: NSDictionary? = [:]
do {
    let myString = try NSAttributedString(
            url: url
            , options: options
            , documentAttributes: &dict
    )
    let encoding = String.Encoding(
        rawValue: (dict?.value(forKey: "CharacterEncoding"))! as! UInt
    )

    string = myString.string
    opened = true
}
catch {
    Logger.write("\(error)")
    string = ""
    let alert = NSAlert()
        
    alert.alertStyle = .critical
    alert.messageText = """
                        File \
                        \(url.absoluteString) \
                        could not be loaded
                        """
    alert.informativeText = "\(error.localizedDescription)"
    _ = alert.runModal()
}

“NSError *错误;” catch 语句尊重处理。

请注意,大于127的字符代码仍然可能会被错误编码,但至少可以打开文本。因此 Remy Lebeau 也是正确的!

在另一个线程中,建议询问用户编码。这很可能会失败,因为即使是我,我也不知道如何回答未知的文本文件。如果不使用适当的高字节代码表,Apple 的 API 就无法正确转换像 CP437(DOS 德语)这样更糟糕的编码。这里 Visual Studio Code 做得非常好,因为它可以正确识别任何编码(至少是我测试过的)并允许将此类文件转换为 UTF-8。

评论: Apple 在 Swift 中的 NSAttributedString 头文件未正确转换,因为它们仅声明了 Objective C 中的弃用内容。

© www.soinside.com 2019 - 2024. All rights reserved.