是否可以可靠地将用户文件自动解码为Unicode? [C#]

时间:2010-02-22 20:58:42

标签: c# string utf-8 multilingual utf-16

我有一个Web应用程序,允许用户上传他们的内容进行处理。处理引擎需要UTF8(我正在从多个用户的文件中编写XML),因此我需要确保能够正确解码上传的文件。

如果我的任何用户都知道他们的文件 编码,我会感到惊讶,我很少希望他们能够正确指定编码(解码器)使用。因此,我的应用程序在解码之前需要进行检测。

这似乎是一个普遍的问题,我很惊讶没有找到解决方案的框架功能或一般配方。是不是我没有搜索有意义的搜索词呢?

我已经实现了BOM感知检测(http://en.wikipedia.org/wiki/Byte_order_mark),但我不确定文件上传的频率是多少用于表示编码,这对大多数非UTF文件都没用

我的问题归结为:

  1. 对于绝大多数文件,BOM感知检测是否足够?
  2. 在BOM检测失败的情况下,是否可以尝试不同的解码器并确定它们是否“有效”? (我的尝试表明答案是“不”。)
  3. 在什么情况下,“有效”文件会因C#编码器/解码器框架而失败?
  4. 是否有一个存储库,其中包含大量具有各种编码的文件用于测试?
  5. 虽然我特别询问C#/ .NET,但我想知道下次我必须要知道Java,Python和其他语言的答案。
  6. 到目前为止,我发现:

    • 带有Ctrl-S字符的“有效”UTF-16文件导致编码为UTF-8抛出异常(非法字符?) (这是一个XML编码异常。 )
    • 使用UTF-8 解码有效的UTF-16文件但提供带有空字符的文本。咦?
    • 目前,我只期望UTF-8,UTF-16和ISO-8859-1文件,但我希望解决方案尽可能是可扩展的。
    • 我现有的输入文件集并不足以发现实时文件会出现的所有问题。
    • 虽然我试图解码的文件是“文本”,但我认为它们通常是用文件中的垃圾字符创建的方法。因此“有效”文件可能不是“纯粹的”。哦,快乐。

    感谢。

5 个答案:

答案 0 :(得分:3)

没有绝对可靠的方法,但你可以用一些启发式方法得到“相当不错”的结果。

  • 如果数据以BOM开头,请使用它。
  • 如果数据包含0字节,则可能是utf-16或ucs-32。您可以通过查看0字节的位置来区分这些,以及这些的big-endian和little-endian变体之间
  • 如果数据可以解码为utf-8(没有错误),则很可能是utf-8(或US-ASCII,但这是utf-8的子集)
  • 接下来,如果您想要国际化,请将浏览器的语言设置映射到该语言最可能的编码。
  • 最后,假设ISO-8859-1

“相当不错”是否“足够好”取决于您的应用程序,当然。如果您需要确定,可能需要将结果显示为预览,并让用户确认数据正确。如果没有,请尝试下一个可能的编码,直到用户满意为止。

注意:如果数据包含乱码,则此算法无效。例如,否则有效的utf-8中的单个垃圾字节将导致utf-8解码失败,从而使算法走错了路径。您可能需要采取其他措施来处理此问题。例如,如果您可以事先识别可能的垃圾,请在尝试确定编码之前将其删除。 (如果剥离过于激进无关紧要,一旦确定了编码,就可以解码原始的未剥离数据,只需将解码器配置为替换无效字符而不是抛出异常。)或者计算解码错误并适当加权。但这可能在很大程度上取决于垃圾的性质,即你可以做出什么样的假设。

答案 1 :(得分:2)

您是否曾尝试从用户那里阅读文件的代表性横截面,通过您的程序运行它们,测试,纠正任何错误并继续前进?

我发现File.ReadAllLines()在各种应用程序中非常有效,而不必担心所有的编码。它似乎处理得很好。

一旦我弄清楚如何正确使用它,Xmlreader()做得相当不错。

也许您可以发布一些具体的数据示例并获得更好的回复。

答案 2 :(得分:1)

这是一个众所周知的问题。您可以尝试执行Internet Explorer正在执行的操作。这是CodeProject中的一个很好的article,它描述了Microsoft对该问题的解决方案。然而,没有任何解决方案是100%准确的,因为一切都是基于heuristcs。假设BOM存在也是不安全的。

答案 3 :(得分:1)

您可能希望查看名为chardet的基于Python的解决方案。它是Mozilla代码的Python端口。虽然您可能无法直接使用它,但它的文档非常值得一读,就像它引用的原始Mozilla文章一样。

答案 4 :(得分:0)

我遇到了类似的问题。我需要一个powershell脚本来确定文件是否是文本编码的(以任何常见的编码方式)。

这绝对不是详尽无遗的,但这是我的解决方案......

PowerShell search script that ignores binary files