检测文本文件编码方式的策略

xiaoxiao2021-02-28  149

分析过程

windows下的Notepad记事本软件在另存的时候可以选择保存的编码方式。 我们可以在记事本中输入同样的文本,如“a严”。

ANSI方式我们用UtralEdit查看二进制信息可以看到: 这里a对应的ANSI编码为61,严对应的ANSI编码为D1 CF。

Unicode BE编码下的二进制信息: 开头的2个字节为FE FF,a的二进制表现为00 61,严的二进制表现为4E 25。

那么我们再来看下Unicode编码方式(Unicode LE)的二进制信息。 我们可以看到开头的2个字节为FF FE,a的二进制表现为61 00,严的二进制表现为25 4E。

我们再来看下UTF-8的二进制信息: 开头3个字节为EF BB BF,a的二进制表现为61,严的二进制表现为E4 B8 A5。 这里要特别注意的是如果是UTF-8 without BOM编码是没有头三个字节的。我们需要按照UTF-8的编码规范去判断字符编码是否符合UTF-8的编码规范。

检测策略

如果2个字节是0xFF 0xFE,则以Unicode(LE)的方式读取 如果2个字节是0xFE 0xFF,则以Unicode BE的方式读取 如果前2个字节是0xEF 0xBB,那么判断第3个字节是不是0xBF,如果是的话就以UTF-8的方式进行读取。 判断是否符合UTF-8的编码规范,如果符合就以UTF-8的方式进行读取 如果以上都不是,则以ANSI的方式进行读取。

代码实现

首先,首先一个enum class作为检测的返回值

enum class Encode { ANSI = 1, UNICODE_LE, UNICODE_BE, UTF8, UTF8_NOBOM };

然后我们可以根据上面总结的规律进行判断。

Encode DetectEncode(const PBYTE pBuffer, long length) { if (pBuffer[0] == 0xFF && pBuffer[1] == 0xFE) { return Encode::UNICODE_LE; } else if (pBuffer[0] == 0xFE && pBuffer[1] == 0xFF) { return Encode::UNICODE_BE; } else if (pBuffer[0] == 0xEF && pBuffer[1] == 0xBB && pBuffer[2] == 0xBF) { return Encode::UTF8; } else if (CheckUnicodeWithoutBOM(pBuffer, length)) { return Encode::UTF8_NOBOM; } else { return Encode::ANSI; } }

下面附上如何检测UTF-8 without BOM的代码实现。

BOOL CheckUnicodeWithoutBOM(const PBYTE pText, long length) { int i; DWORD nBytes = 0; UCHAR chr; BOOL bAllAscii = TRUE; for (i = 0; i < length; i++) { chr = *(pText + i); if ((chr & 0x80) != 0) bAllAscii = FALSE; if (nBytes == 0) { if (chr >= 0x80) { if (chr >= 0xFC && chr <= 0xFD) nBytes = 6; else if (chr >= 0xF8) nBytes = 5; else if (chr >= 0xF0) nBytes = 4; else if (chr >= 0xE0) nBytes = 3; else if (chr >= 0xC0) nBytes = 2; else { return FALSE; } nBytes--; } } else { if ((chr & 0xC0) != 0x80) { return FALSE; } nBytes--; } } if (nBytes > 0) { return FALSE; } if (bAllAscii) { return FALSE; } return TRUE; }

参考资料

The Notepad encoding detection issues keep coming up 简析Windows Notepad里可选的字符编码 字符编码笔记:ASCII,Unicode和UTF-8 字符集和字符编码(Charset & Encoding)

转载请注明原文地址: https://www.6miu.com/read-74045.html

最新回复(0)