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的编码规范。
首先,首先一个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)
