在我们的应用程序中,我们从不同的来源接收文本文件(.txt, .csv等)。读取时,这些文件有时包含垃圾,因为这些文件是在不同的/未知的代码页中创建的。

是否有一种方法(自动)检测文本文件的代码页?

detectEncodingFromByteOrderMarks,在StreamReader构造函数上,适用于UTF8和其他unicode标记的文件,但我正在寻找一种方法来检测代码页,如ibm850, windows1252。


谢谢你的回答,这就是我所做的。

我们收到的文件来自最终用户,他们没有关于代码页的线索。接收者也是最终用户,到目前为止,这是他们对代码页的了解:代码页存在,并且令人讨厌。

解决方案:

在记事本中打开收到的文件,查看一段乱码的文本。如果有人叫François之类的,凭你的智商你就能猜出来。 我已经创建了一个小应用程序,用户可以使用它打开文件,并输入用户知道它将出现在文件中的文本,当使用正确的代码页时。 遍历所有代码页,并显示包含用户提供的文本的解决方案的代码页。 如果多个代码页同时弹出,请用户指定更多文本。


当前回答

我实际上是在寻找一种通用的,而不是编程的方法来检测文件编码,但我还没有找到。 通过测试不同的编码,我发现我的文本是UTF-7。

我第一次做的是 StreamReader文件= file . opentext (fullfilename);

我不得不把它改成: StreamReader文件=新的StreamReader(fullfilename, System.Text.Encoding.UTF7);

OpenText假设它是UTF-8。

你也可以像这样创建StreamReader new StreamReader(fullfilename, true),第二个参数意味着它应该尝试从文件的byteordermark中检测编码,但这在我的例子中不起作用。

其他回答

我知道现在提这个问题已经很晚了,而且这个解决方案不会吸引一些人(因为它以英语为中心的偏见和缺乏统计/实证测试),但它对我来说非常有效,特别是在处理上传的CSV数据方面:

http://www.architectshack.com/TextFileEncodingDetector.ashx

优点:

内置BOM检测 默认/回退编码可定制 相当可靠(以我的经验)的西欧文件包含一些奇异的数据(如法国名称)与混合UTF-8和拉丁-1风格的文件-基本上大部分美国和西欧环境。

注意:我是编写这个类的人,所以显然要持保留态度!:)

notepad++具有这个功能。它还支持对其进行更改。

在寻找不同的解决方案时,我发现

https://code.google.com/p/ude/

这个溶液有点重。

我需要一些基本的编码检测,基于4个第一个字节和可能的xml字符集检测-所以我从互联网上取了一些样本源代码,并添加了稍微修改的版本

http://lists.w3.org/Archives/Public/www-validator/2002Aug/0084.html

为Java编写的。

    public static Encoding DetectEncoding(byte[] fileContent)
    {
        if (fileContent == null)
            throw new ArgumentNullException();

        if (fileContent.Length < 2)
            return Encoding.ASCII;      // Default fallback

        if (fileContent[0] == 0xff
            && fileContent[1] == 0xfe
            && (fileContent.Length < 4
                || fileContent[2] != 0
                || fileContent[3] != 0
                )
            )
            return Encoding.Unicode;

        if (fileContent[0] == 0xfe
            && fileContent[1] == 0xff
            )
            return Encoding.BigEndianUnicode;

        if (fileContent.Length < 3)
            return null;

        if (fileContent[0] == 0xef && fileContent[1] == 0xbb && fileContent[2] == 0xbf)
            return Encoding.UTF8;

        if (fileContent[0] == 0x2b && fileContent[1] == 0x2f && fileContent[2] == 0x76)
            return Encoding.UTF7;

        if (fileContent.Length < 4)
            return null;

        if (fileContent[0] == 0xff && fileContent[1] == 0xfe && fileContent[2] == 0 && fileContent[3] == 0)
            return Encoding.UTF32;

        if (fileContent[0] == 0 && fileContent[1] == 0 && fileContent[2] == 0xfe && fileContent[3] == 0xff)
            return Encoding.GetEncoding(12001);

        String probe;
        int len = fileContent.Length;

        if( fileContent.Length >= 128 ) len = 128;
        probe = Encoding.ASCII.GetString(fileContent, 0, len);

        MatchCollection mc = Regex.Matches(probe, "^<\\?xml[^<>]*encoding[ \\t\\n\\r]?=[\\t\\n\\r]?['\"]([A-Za-z]([A-Za-z0-9._]|-)*)", RegexOptions.Singleline);
        // Add '[0].Groups[1].Value' to the end to test regex

        if( mc.Count == 1 && mc[0].Groups.Count >= 2 )
        {
            // Typically picks up 'UTF-8' string
            Encoding enc = null;

            try {
                enc = Encoding.GetEncoding( mc[0].Groups[1].Value );
            }catch (Exception ) { }

            if( enc != null )
                return enc;
        }

        return Encoding.ASCII;      // Default fallback
    }

从文件中读取1024字节就足够了,但我加载的是整个文件。

由于它基本上归结为启发式,因此使用以前从同一来源收到的文件的编码作为第一个提示可能会有所帮助。

大多数人(或应用程序)每次都以几乎相同的顺序做事,通常是在同一台机器上,所以当Bob创建一个.csv文件并将其发送给Mary时,它很可能总是使用Windows-1252或他的机器默认的任何文件。

在可能的情况下,一点客户培训也不会有什么坏处:-)

“uchardet”工具使用每个字符集的字符频率分布模型很好地做到了这一点。更大的文件和更“典型”的文件具有更强的可信度(显然)。

在ubuntu上,你只需要apt-get install uchardet。

在其他系统上,从这里获取源代码、用法和文档:https://github.com/BYVoid/uchardet