工作中用到了,就寫了一個。
GBK編碼從0x8140-0xFEFE,去除0xxx7F這部分。包括了所用的中日韓字符集。
判斷是否爲GBK可以用isGBKChe 或 isGBKChe2,都可以。
一個是從區間判斷,一個是從第一個字節的頭位爲一這個特性判斷。
typedef unsigned char var_u1;
#define isZone(p,a,b) ( (p) >= (a) && (p) <= (b) )
#define isGBKChe(p) (isZone(*(var_u1*)p,0x81,0xFE) && isZone(*(var_u1*)(p+1),0x40,0xFE) && *(p+1) != 0x7F )
#define isGBKChe2(p) (*(p)<0)
static int cutbuf(char* p, int len, int size)
{
if( len<= size )
return len;
char *pEnd = p + size - 1;
char *pCur = p;
if( !isGBKChe(pEnd) )
return size;
while(pCur<pEnd)
{
if( isGBKChe(pCur) )
pCur+=2;
else
pCur++;
}
return pCur-p;
}
utf-8判斷遵循的是這個屬性:
UTF-8的編碼規則很簡單,只有二條:
1)對於單字節的符號,字節的第一位設爲0,後面7位爲這個符號的unicode碼。因此對於英語字母,UTF-8編碼和ASCII碼是相同的。
2)對於n字節的符號(n>1),第一個字節的前n位都設爲1,第n+1位設爲0,後面字節的前兩位一律設爲10。剩下的沒有提及的二進制位,全部爲這個符號的unicode碼。
下表總結了編碼規則,字母x表示可用編碼的位。
Unicode符號範圍 | UTF-8編碼方式
(十六進制) | (二進制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
漢字位於第三區間內,由三字節編碼組成。
所以只要鑑別第一字節的頭四個字位,後兩位的前兩個字位即可。
#define isUTF8Che(p) ( (*(var_u1*)(p))>>4 == 0x0E && (*(var_u1*)(p+1))>>6 == 0x02 && (*(var_u1*)(p+2))>>6 == 0x02 )
static int qi_cutbuf_utf8(var_1* p, int len, int size)
{
if( len<= size )
return len;
if( *(p + size - 1) >= 0 )
return size;
if( size < 3 )
return 0;
char *pEnd = p + size;
char *pCur = p + size - 2;
while(pCur>p && (*(var_u1*)(pCur))>>4 != 0x0E )
{
pCur--;
}
while(pCur<pEnd)
{
if( isUTF8Che(pCur) )
pCur+=3;
else
pCur++;
}
if( pCur > pEnd )
pCur -= 3;
return pCur-p;
}
中間做了個優化,
1.如果截取末尾爲正數,可以認爲該字符爲單字符編碼,直接截取即可。
2.如果小於3字節,返回0長度。
3.向前找1110 xxxx或大於零的字節,然後從該位置向後計算,這樣可以不用從頭遍歷。
這兩個文章是介紹編碼字符集的:
字符編碼簡介:ASCII,Unicode,UTF-8,GB2312:http://www.cnblogs.com/mjgforever/archive/2008/02/27/1083135.html
字符集GBK和UTF8的區別說明:http://space.itpub.net/55022/viewspace-713901