/*
unicode符号范围 16进制 | TUF8编码方式 2进制
----------------------------------------------------------------------------------------
1 | 0000 0000 0000 007F | 0XXXXXXX
2 | 0000 0000 0000 07FF | 110XXXXX 10XXXXXX
3 | 0000 0000 0000 FFFF | 1110XXXX 10XXXXXX 10XXXXXX
4 | 0000 0000 0010 FFFF | 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
5 | 0000 0000 03FF FFFF | 111110XX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX
6 | 0000 0000 7FFF FFFF | 1111110X 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX
按字节顺序遍历字符串 (使用循环的原因: 要按字节为单位检测完所有字节才能确定该字符串是否为TUF编码的字符串)
1) 单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位
2) 获取一个UTF8字符的长度, 单位为字节 (使用循环的原因: 不清楚当前TUF8下的字符占用一个字节还是多个字节)
3) UTF8字符是单个字节, 错误的UTF8编码
4) 检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于0x80, 错误的UTF8编码 (使用循环的原因: 不清楚当前TUF8下的字符出来首字节外还占用了几个字节)
循环结束, 正确的UTF8编码
*/
BOOL CEncode::CheckUtf8(LPBYTE pStr)
{
auto p = pStr;
int nCount = 0;
int nLength = strlen((LPCSTR)pStr); // 原始字符串的字节长度
// 按字节顺序遍历字符串
while (*p) // '\0'是字符串的结束标记
{
auto c = *p++; // 获取当前字节, 指针指向相邻的下一个字节
// 1) 单字节的UTF8字符, 字节的最高位为0, 继续检测相邻的下一个字节的最高位, 默认单字节的字符为UTF8编码的字符
if ((c & 0x80) == 0)
if (++nCount == nLength) // 区分ANSI与UTF8编码, ANSI的字符总个数等于字节总数, UTF8的字符总数不等于字节总数
return FALSE;
else continue;
// 2) 获取一个UTF8字符的长度, 单位为字节
int nBytes = 0; // 一个UTF8字符的长度, 单位为字节
do nBytes++; while ((c = c << 1) & 0x80); // 当前字节左移一位后,最高位为0, 停止循环
if (nBytes == 1) return FALSE; // 单字节的UTF8在前面处理过. 这里出现就是缺损的编码字符,错误的UTF8编码
// 4) 检测一个UTF8字符的非首字节,最高两位(截取的掩码是0xC0),不等于二进制的10(0x80), 就是错误的UTF8编码
for (int i = 1; i < nBytes; i++) // 检测字符串中某一个UTF8字符的非首字节
if ((*p++ & 0xC0) != 0x80)
return FALSE;
}
// 循环结束, 正确的UTF8编码
return TRUE;
}