如何检测文本文件的字符编码?
-
12-10-2019 - |
题
我尝试检测文件中使用了哪个字符编码。
我尝试使用此代码以获取标准编码
public static Encoding GetFileEncoding(string srcFile)
{
// *** Use Default of Encoding.Default (Ansi CodePage)
Encoding enc = Encoding.Default;
// *** Detect byte order mark if any - otherwise assume default
byte[] buffer = new byte[5];
FileStream file = new FileStream(srcFile, FileMode.Open);
file.Read(buffer, 0, 5);
file.Close();
if (buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf)
enc = Encoding.UTF8;
else if (buffer[0] == 0xfe && buffer[1] == 0xff)
enc = Encoding.Unicode;
else if (buffer[0] == 0 && buffer[1] == 0 && buffer[2] == 0xfe && buffer[3] == 0xff)
enc = Encoding.UTF32;
else if (buffer[0] == 0x2b && buffer[1] == 0x2f && buffer[2] == 0x76)
enc = Encoding.UTF7;
else if (buffer[0] == 0xFE && buffer[1] == 0xFF)
// 1201 unicodeFFFE Unicode (Big-Endian)
enc = Encoding.GetEncoding(1201);
else if (buffer[0] == 0xFF && buffer[1] == 0xFE)
// 1200 utf-16 Unicode
enc = Encoding.GetEncoding(1200);
return enc;
}
我的五个字节是60、118、56、46和49。
是否有图表显示编码哪个与这五个字节匹配的图表?
解决方案
您不能依靠BOM的文件。 UTF-8不需要它。而且非固定编码甚至没有BOM。但是,还有其他检测编码的方法。
UTF-32
BOM为00 00 fe ff(be)或ff fe 00 00(对于LE)。
但是即使没有BOM,UTF-32也很容易检测到。这是因为Unicode代码点范围仅限于U+10FFFF,因此UTF-32单元始终具有模式00 {00-10} XX XX(for Be)或XX XX XX {00-10} 00(用于LE) 。如果数据的长度为4的倍数,并且遵循这些模式之一,则可以安全地假设其是UTF-32。由于面向字节的编码中00字节的稀有性,误报几乎是不可能的。
美国
没有生物,但是您不需要。通过在80FF范围内缺少字节,可以轻松地识别ASCII。
UTF-8
BOM是EF BB BF。但是你不能依靠这个。许多UTF-8文件没有BOM,尤其是当它们起源于非窗口系统时。
但是您可以安全地假设,如果文件验证为UTF-8,则 是 UTF-8。误报很少见。
具体而言,鉴于数据不是ASCII,因此2字节序列的假阳性仅为3.9%(1920/49152)。对于7字节序列,它不到1%。对于12字节序列,它不到0.1%。对于24字节的序列,它不到一百万分之一。
UTF-16
BOM是Fe FF(用于BE)或FF FE(对于LE)。请注意,在UTF-32LE BOM的开头找到UTF-16LE BOM,因此请先检查UTF-32。
如果您碰巧拥有一个主要由ISO-8859-1字符组成的文件,则文件字节的一半为00也将是UTF-16的强烈指标。
否则,识别没有BOM的UTF-16的唯一可靠方法是寻找替代配对(D [8-B] XX D [CF] XX),但是非BMP字符很少使用,无法使这种方法实用。
XML
如果您的文件从字节3C 3F 78 6D 6C开始(即,ASCII字符” encoding=
宣言。如果存在,请使用该编码。如果不存在,则假设UTF-8,即默认XML编码。
如果您需要支持EBCDIC,也可以寻找等效序列4C 6F A7 94 93。
通常,如果您具有包含编码声明的文件格式,请查找该声明而不是试图猜测编码。
以上都不是
还有数百个其他编码,需要更多的努力来检测。我建议尝试 Mozilla的Charset探测器 或者 一个.NET端口.
合理的默认值
如果您排除了UTF编码,并且没有指向不同编码的编码声明或统计检测 ISO-8859-1 或密切相关的 Windows-1252. 。 (请注意,最新的HTML标准 需要 “ ISO-8859-1”声明要解释为Windows-1252。 UTF-8。
其他提示
如果您想寻求“简单”的解决方案,您可能会发现我组合在一起有用:
http://www.architectshack.com/textfileencodingdetector.ashx
它首先自动进行BOM检测,然后尝试区分无BOM的Unicode编码,与其他默认编码(通常Windows-1252,错误地标记为encoding.ascii in .NET中)。
如上所述,涉及nChardet或mlang的“更重”解决方案可能更合适,正如我在此类概述页面上注明的那样,最好的是在可能的话上提供与用户的某种形式的交互性,因为只有在这里,没有100%的检测率!
利用 StreamReader
并指导它为您检测编码:
using (var reader = new System.IO.StreamReader(path, true))
{
var currentEncoding = reader.CurrentEncoding;
}
并使用 代码页标识符 https://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(V=VS.85).aspx为了根据它切换逻辑。
这里有几个答案,但是没有人发布了有用的代码。
这是我的代码检测Microsoft在StreamReader类中检测到的所有编码。
显然,您必须在打开流之后立即调用此功能,然后再读取流中的其他内容,因为BOM是流中的第一个字节。
此功能需要一个可以寻找的流(例如文件流)。如果您有一个无法寻求的流,则必须编写一个更复杂的代码,该代码返回具有已经读取但不是BOM的字节的字节缓冲区。
/// <summary>
/// UTF8 : EF BB BF
/// UTF16 BE: FE FF
/// UTF16 LE: FF FE
/// UTF32 BE: 00 00 FE FF
/// UTF32 LE: FF FE 00 00
/// </summary>
public static Encoding DetectEncoding(Stream i_Stream)
{
if (!i_Stream.CanSeek || !i_Stream.CanRead)
throw new Exception("DetectEncoding() requires a seekable and readable Stream");
// Try to read 4 bytes. If the stream is shorter, less bytes will be read.
Byte[] u8_Buf = new Byte[4];
int s32_Count = i_Stream.Read(u8_Buf, 0, 4);
if (s32_Count >= 2)
{
if (u8_Buf[0] == 0xFE && u8_Buf[1] == 0xFF)
{
i_Stream.Position = 2;
return new UnicodeEncoding(true, true);
}
if (u8_Buf[0] == 0xFF && u8_Buf[1] == 0xFE)
{
if (s32_Count >= 4 && u8_Buf[2] == 0 && u8_Buf[3] == 0)
{
i_Stream.Position = 4;
return new UTF32Encoding(false, true);
}
else
{
i_Stream.Position = 2;
return new UnicodeEncoding(false, true);
}
}
if (s32_Count >= 3 && u8_Buf[0] == 0xEF && u8_Buf[1] == 0xBB && u8_Buf[2] == 0xBF)
{
i_Stream.Position = 3;
return Encoding.UTF8;
}
if (s32_Count >= 4 && u8_Buf[0] == 0 && u8_Buf[1] == 0 && u8_Buf[2] == 0xFE && u8_Buf[3] == 0xFF)
{
i_Stream.Position = 4;
return new UTF32Encoding(true, true);
}
}
i_Stream.Position = 0;
return Encoding.Default;
}
您应该阅读以下内容: 如何检测文本文件的编码/编码
如果您的文件以60、118、56、46和49的字节开始,则您有一个模棱两可的情况。它可以是UTF-8(无BOM)或任何单个字节编码,例如ASCII,ANSI,ISO-8859-1等。
我用 Ude 那是Mozilla通用Charset检测器的C#港口。它易于使用,并给出一些非常好的效果。