轉自:http://blog.csdn.net/jiangqin115/article/details/42684017
UTF-8編碼的文本文檔,有的帶有BOM (Byte Order Mark, 字節序標志),即0xEF, 0xBB, 0xBF,有的沒有。Windows下的txt文本編輯器在保存UTF-8格式的文本文檔時會自動添加BOM到文件頭。在判斷這類文檔時,可以根據文檔的前3個字節來進行判斷。然而BOM不是必需的,而且也不是推薦的。對不希望UTF-8文檔帶有BOM的程序會帶來兼容性問題,例如Java編譯器在編譯帶有BOM的UTF-8源文件時就會出錯。而且BOM去掉了UTF-8一個期望的特性,即是在文本全部是ASCII字符時UTF-8是和ASCII一致的,即UTF-8向下兼容ASCII。
在具體判斷時,如果文檔不帶有BOM,就無法根據BOM做出判斷,而且IsTextUnicode API也無法對UTF-8編碼的Unicode字符串做出判斷。那在編程判斷時就要根據UTF-8字符編碼的規律進行判斷了。
UTF-8是一種多字節編碼的字符集,表示一個Unicode字符時,它可以是1個至多個字節,在表示上有規律:
1字節:0xxxxxxx
2字節:110xxxxx 10xxxxxx
3字節:1110xxxx 10xxxxxx 10xxxxxx
4字節:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
這樣就可以根據上面的特征對字符串進行遍歷來判斷一個字符串是不是UTF-8編碼了。應該指出的是UTF-8字符串的各個字節的取值有一定的范圍,並不是所有的值都是有效的UTF-8字符,但是一般的應用的情況下這樣的判斷在對足夠長的字符串及是比較精確了,而且實現也比較簡單。具體的字節取值范圍可以參見"Unicode Explained"一書中的6.4.3。另外BOM本身也符合3字節UTF-8字符編碼規律,所以本方法對帶BOM的UTF-8字符串也是有效的。
1. 判斷文本是否UTF編碼
在下面程序中對最大3字節長的UTF-8字符進行了判斷,在實際情況下,幾乎所有能用到的UTF-8字符最長就是3個字節
1 bool IsUTF8(const void* pBuffer, long size) 2 { 3 bool IsUTF8 = true; 4 unsigned char* start = (unsigned char*)pBuffer; 5 unsigned char* end = (unsigned char*)pBuffer + size; 6 while (start < end) 7 { 8 if (*start < 0x80) // (10000000): 值小於0x80的為ASCII字符 9 { 10 start++; 11 } 12 else if (*start < (0xC0)) // (11000000): 值介於0x80與0xC0之間的為無效UTF-8字符 13 { 14 IsUTF8 = false; 15 break; 16 } 17 else if (*start < (0xE0)) // (11100000): 此范圍內為2字節UTF-8字符 18 { 19 if (start >= end - 1) 20 { 21 break; 22 } 23 24 if ((start[1] & (0xC0)) != 0x80) 25 { 26 IsUTF8 = false; 27 break; 28 } 29 30 start += 2; 31 } 32 else if (*start < (0xF0)) // (11110000): 此范圍內為3字節UTF-8字符 33 { 34 if (start >= end - 2) 35 { 36 break; 37 } 38 39 if ((start[1] & (0xC0)) != 0x80 || (start[2] & (0xC0)) != 0x80) 40 { 41 IsUTF8 = false; 42 break; 43 } 44 45 start += 3; 46 } 47 else 48 { 49 IsUTF8 = false; 50 break; 51 } 52 } 53 54 return IsUTF8; 55 }
2. 判斷文件是否UTF-8編碼:
1 bool CConvertCharset::IsUTF8File(const char* pFileName) 2 { 3 FILE *f = NULL; 4 fopen_s(&f, pFileName, "rb"); 5 if (NULL == f) 6 { 7 return false; 8 } 9 10 fseek(f, 0, SEEK_END); 11 long lSize = ftell(f); 12 fseek(f, 0, SEEK_SET); //或rewind(f); 13 14 char *pBuff = new char[lSize + 1]; 15 memset(pBuff, 0, lSize + 1); 16 fread(pBuff, lSize, 1, f); 17 fclose(f); 18 19 bool bIsUTF8 = IsUTF8Text(pBuff, lSize); 20 delete []pBuff; 21 pBuff = NULL; 22 23 return bIsUTF8; 24 }