在我们的应用中,我们收到的文本文件(.txt
,.csv
从不同的来源,等等).在阅读时,这些文件有时会包含垃圾,因为文件是在不同的/未知的代码页中创建的.
有没有办法(自动)检测文本文件的代码页?
的detectEncodingFromByteOrderMarks
,对StreamReader
构造,工程UTF8
和其他的Unicode标文件,但是我正在寻找一种方法来检测代码页,像ibm850
,windows1252
.
谢谢你的回答,这就是我所做的.
我们收到的文件来自最终用户,他们没有关于代码页的线索.接收者也是最终用户,到目前为止,这是他们对代码页的了解:代码页存在,并且令人讨厌.
解:
在记事本中打开收到的文件,查看一段乱码文本.如果有人被称为弗朗索瓦(François)或其他东西,那么凭借你的人类智慧你可以猜到这一点
我创建了一个小应用程序,用户可以使用该应用程序打开文件,并在使用正确的代码页时输入用户知道它将出现在文件中的文本.
遍历所有代码页,并显示提供用户提供的文本解决方案的代码页.
如果弹出一个代码页,请让用户指定更多文本.
JV... 258
你无法检测代码页,需要告诉它.您可以分析字节并猜测它,但这可能会产生一些奇怪的(有时是有趣的)结果.我现在找不到它,但我确信记事本可以用中文显示英文文本.
无论如何,这是你需要阅读的内容: 绝对最低每个软件开发人员绝对必须知道Unicode和字符集(没有借口!).
特别是乔尔说:
关于编码的最重要事实
如果你完全忘记我刚才解释的一切,请记住一个非常重要的事实.在不知道它使用什么编码的情况下拥有字符串是没有意义的.你不能再把头埋在沙子里,假装"普通"文字是ASCII.没有像平原那样的东西.
如果您有字符串,内存,文件或电子邮件消息,则必须知道它所处的编码,或者您无法解释它或正确地将其显示给用户.
我赞成这个答案有两个原因.首先,说"你需要被告知"是没有用的.谁会告诉我,他们会通过什么媒介这样做?如果我是保存文件的人,我会问谁?我?其次,该文章作为回答问题的资源并不是特别有用.这篇文章更多的是以David Sedaris风格编写的编码历史.我很欣赏叙述,但它并不是简单/直接回答这个问题. (41认同)
@geneorama,我认为Joel的文章比我以前更好地解决了你的问题,但是这里......媒介肯定取决于收到文本的环境.更好的是文件(或其他)包含该信息(我正在考虑HTML和XML).否则,应允许发送文本的人提供该信息.如果您是创建该文件的人,您怎么能不知道它使用的是什么编码? (8认同)
@geneorama,续......最后,我认为文章没有回答这个问题的主要原因是因为这个问题没有简单的答案.如果问题是"我怎么能猜..."那么我的回答会有所不同. (4认同)
Tomer Gabel.. 31
如果您希望检测非UTF编码(即没有BOM),那么您基本上可以使用文本的启发式和统计分析.您可能需要查看有关通用字符集检测的Mozilla文章(相同链接,通过Wayback Machine更好地格式化).
你无法检测代码页,需要告诉它.您可以分析字节并猜测它,但这可能会产生一些奇怪的(有时是有趣的)结果.我现在找不到它,但我确信记事本可以用中文显示英文文本.
无论如何,这是你需要阅读的内容: 绝对最低每个软件开发人员绝对必须知道Unicode和字符集(没有借口!).
特别是乔尔说:
关于编码的最重要事实
如果你完全忘记我刚才解释的一切,请记住一个非常重要的事实.在不知道它使用什么编码的情况下拥有字符串是没有意义的.你不能再把头埋在沙子里,假装"普通"文字是ASCII.没有像平原那样的东西.
如果您有字符串,内存,文件或电子邮件消息,则必须知道它所处的编码,或者您无法解释它或正确地将其显示给用户.
如果您希望检测非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."); } } }
您无法检测代码页
这显然是错误的.每个Web浏览器都有某种通用字符集检测器来处理没有任何编码指示的页面.Firefox有一个.您可以下载代码并查看它是如何做到的.在这里查看一些文档.基本上,它是一种启发式方法,但效果非常好.
给定合理数量的文本,甚至可以检测语言.
这是我刚刚使用Google发现的另一个:
我知道这个问题已经很晚了,这个解决方案不会吸引一些人(因为它以英语为中心的偏见和缺乏统计/经验测试),但它对我来说非常有效,特别是对于处理上传的CSV数据:
http://www.architectshack.com/TextFileEncodingDetector.ashx
好处:
内置BOM检测
默认/后备编码可自定义
非常可靠(根据我的经验),基于西欧文件,包含一些混合了UTF-8和Latin-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个字节,但我正在加载整个文件.
如果有人正在寻找93.9%的解决方案.这对我有用:
public static class StreamExtension { ////// Convert the content to a string. /// /// The stream. ///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(); } } }