如何检测文本文件的编码/代码页

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

有没有办法(自动)检测文本文件的代码页?

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


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

我们收到的文件来自最终用户,他们没有关于代码页的线索。 接收者也是最终用户,到目前为止他们知道的关于代码页的问题:代码页存在,而且很烦人。

解:

  • 在记事本中打开收到的文件,看一个乱码的文本。 如果有人被称为弗朗索瓦什么东西,用你的人类智慧,你可以猜测这个。
  • 我创build了一个小应用程序,用户可以使用该应用程序打开文件,并在使用正确的代码页时input用户知道该文件将出现在文件中的文本。
  • 循环遍历所有代码页,并显示用户提供的文本解决scheme。
  • 如果popup更多的代码页,请让用户指定更多的文本。

你无法检测到代码页,你需要被告知。 你可以分析字节并猜测它,但是这可能会导致一些奇怪的(有时是有趣的)结果。 我现在找不到它,但是我确定记事本可以被诱骗到显示中文的英文文本。

无论如何,这是你需要阅读的: 绝对最小每个软件开发人员绝对,积极必须知道Unicode和字符集(没有借口!) 。

具体来说,乔尔说:

关于编码的一个最重要的事实

如果你完全忘记了我刚刚解释的一切,请记住一个非常重要的事实。 有一个string没有意义,不知道它使用什么编码。 你不能再把头埋在沙子里,假装“纯文本”是ASCII。 没有像纯文本那样的东西。

如果你有一个string,在内存中,在一个文件中,或在一个电子邮件信息,你必须知道它是在什么编码,或者你不能解释或显示给用户正确。

如果你想检测非UTF编码(即没有BOM),你基本上是对文本的启发式和统计分析。 您可能需要查看Mozilla有关通用字符集检测的论文 ( 同样的链接,通过Wayback Machine更好的格式化 )。

你有没有试过Mozilla Universal Charset Detector的C#端口

来自http://code.google.com/p/ude/的示例;

 public static void Main(String[] args) { string filename = args[0]; using (FileStream fs = File.OpenRead(filename)) { Ude.CharsetDetector cdet = new Ude.CharsetDetector(); cdet.Feed(fs); cdet.DataEnd(); if (cdet.Charset != null) { Console.WriteLine("Charset: {0}, confidence: {1}", cdet.Charset, cdet.Confidence); } else { Console.WriteLine("Detection failed."); } } } 

您无法检测到代码页

这显然是错误的。 每个网页浏览器都有一些通用的字符集检测器来处理没有任何编码指示的页面。 Firefox有一个。 你可以下载代码,看看它是如何做到的。 在这里看到一些文档。 基本上,这是一个启发式的,但真的很好。

给定合理数量的文本,甚至可以检测到该语言。

这是我刚刚使用Google发现的另一个 :

我知道这个问题已经很晚了,这个解决scheme不会吸引一些人(因为它以英语为中心的偏见,缺乏统计/经验性的testing),但是对我来说非常好,特别是处理上传的CSV数据:

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

优点:

  • BOM检测内置
  • 默认/后备编码可自定义
  • 对于基于西欧的文件,包含一些奇特的数据(例如法语名称)以及UTF-8和Latin-1风格的文件(基本上是美国和西欧大部分环境)的相当可靠的(以我的经验)。

注意:我是写这个课的,所以显然要拿一粒盐! 🙂

Notepad ++具有开箱即用的function。 它也支持改变它。

寻找不同的解决scheme,我发现

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

这个解决scheme有点沉重。

我需要一些基本的编码检测,基于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个字节就足够了,但是我正在加载整个文件。

我在Python中做了类似的事情。 基本上,你需要来自各种编码的大量样本数据,这些编码通过滑动的双字节窗口分解并存储在字典(散列)中,键入提供编码列表的值的字节对。

鉴于该字典(散列),你把你的input文本和:

  • 如果它以任何BOM字符(UTF-16-BE的'\ xfe \ xff',UTF-16-LE的'\ xff \ xfe',UTF-8的'\ xef \ xbb \ xbf'等)开头,按照build议对待它
  • 如果不是,则取足够大的文本样本,取样本的所有字节对,并select字典中最不常见的编码。

如果您还采样了以任何BOM开头的UTF编码文本,则第二步将涵盖从第一步开始滑动的文本。

到目前为止,它适用于我(样本数据和随后的input数据是各种语言的字幕),错误率正在降低。

如果有人正在寻找一个93.9%的解决scheme。 这适用于我:

 public static class StreamExtension { /// <summary> /// Convert the content to a string. /// </summary> /// <param name="stream">The stream.</param> /// <returns></returns> public static string ReadAsString(this Stream stream) { var startPosition = stream.Position; try { // 1. Check for a BOM // 2. or try with UTF-8. The most (86.3%) used encoding. Visit: http://w3techs.com/technologies/overview/character_encoding/all/ var streamReader = new StreamReader(stream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true), detectEncodingFromByteOrderMarks: true); return streamReader.ReadToEnd(); } catch (DecoderFallbackException ex) { stream.Position = startPosition; // 3. The second most (6.7%) used encoding is ISO-8859-1. So use Windows-1252 (0.9%, also know as ANSI), which is a superset of ISO-8859-1. var streamReader = new StreamReader(stream, Encoding.GetEncoding(1252)); return streamReader.ReadToEnd(); } } } 

StreamReader类的构造函数采用“检测编码”参数。

“uchardet”这个工具对每个字符集都使用字符频率分布模型。 较大的文件和更多的“典型”文件有更多的信心(显然)。

在Ubuntu上,你只需apt-get install uchardet

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

如果你可以链接到一个C库,你可以使用libenca 。 请参阅http://cihar.com/software/enca/ 。 从手册页:

Enca读取给定的文本文件,或者在没有给定文本文件的情况下读取标准input,并使用有关其语言的知识(必须由您支持)以及parsing,统计分析,猜测和黑魔法的混合来确定其编码。

这是GPL v2。

有同样的问题,但没有find一个很好的解决scheme,但自动检测。 现在即时通讯使用PsPad(www.pspad.com);)工作正常

由于它基本上归结为启发式,所以可能有助于使用来自相同源的先前接收的文件的编码作为第一提示。

大多数人(或应用程序)每次都以相同的顺序进行操作,通常在同一台机器上,所以当Bob创build.csv文件并将其发送给Mary时,它总是使用Windows-1252或无论他的机器默认。

在可能的情况下,客户培训一点也不会伤害:-)

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

所以我第一次在做什么:StreamReader file = File.OpenText(fullfilename);

我不得不将其更改为:StreamReader file = new StreamReader(fullfilename,System.Text.Encoding.UTF7);

OpenText假定它是UTF-8。

你也可以像这个新的StreamReader(fullfilename,true)一样创buildStreamReader,第二个参数意味着它应该尝试检测文件的字节顺序的编码,但是在我的情况下这不起作用。

作为ITmeze后附加,我已经使用此function来转换Mozilla Universal Charset Detector的C#端口的输出

  private Encoding GetEncodingFromString(string encoding) { try { return Encoding.GetEncoding(encoding); } catch { return Encoding.ASCII; } } 

MSDN

在AkelPad中打开文件(或复制/粘贴乱码文本),进入编辑 – >select – >重新编码… – >检查“自动检测”。

读取文件时,我使用此代码来检测Unicode和Windows默认的ANSI代码页。 对于其他编码,内容检查是必要的,手动或通过编程。 这可以用来保存与打开时相同的编码的文本。 (我使用VB.NET)

 'Works for Default and unicode (auto detect) Dim mystreamreader As New StreamReader(LocalFileName, Encoding.Default) MyEditTextBox.Text = mystreamreader.ReadToEnd() Debug.Print(mystreamreader.CurrentEncoding.CodePage) 'Autodetected encoding mystreamreader.Close()