字符集是将一个数值对应到一个字符的映射表,有Unicode和ANSI之分,Unicode为通用字符集,而对于ANSI(多字节)来说,不同的国家有其不同的字符集,如中文的GB2312字符集等。
字符编码是字符集的存储实现,如Unicode编码的2字节存储以及ANSI的多字节存储。
概念容易混乱,ANSI和Unicode是字符集没错,但同时也是一种字符编码。
Unicode编码中所有的字符都是以2字节存储,而英文字母的存储实际只需要1个字节,因此相对于以英文为母语的国家来说,这样的存储方式是一种极大的浪费,UTF8编码也就应运而生。它是Unicode字符集的另一种编码实现形式,具体细节如下:
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
其中的x对应的是Unicode字符集中的值,可以看出:
以1个字节表示一个字符时可以表示的Unicode值为[0, 0X7F]
以2个字节表示一个字符时可以表示的Unicode值为(0X7F, 0X7FF]
以3个字节表示一个字符时可以表示的Unicode值为(0X7FF, 0XFFFF]
以4个字节表示一个字符时可以表示的Unicode值为(0XFFFF, 0X10FFFF]
Unicode字符集目前只存在于这个范围之内,而实际中UTF8还可以实现更多的字符。
对于一字节实现的字符,其实际值与ASCII码值一致,而对于多字节实现的字符,最高位字节从高位开始连续的1的位数表示了这个字符是以多少个字节实现的,而除最高字节外,其他字节的高位均以10开头,最高位在连续的1之后也需补一个0,剩下的x所表示的便是此字符对应的Unicode值。
UTF8编码的多字节存储在小端机器上是大端存储,大端机器没有接触过。
C语言实现的Unicode与UTF8编码的转换,参照MultiByteToWideChar和WideCharToMultiByte的功能实现
int UnicodeToUTF8(const wchar_t* szSrc, int nSrc, char* szDest, int nDest)
{
int i = 0;
unsigned int num;
for(int j = 0; j < nSrc; j++)
{
num = (UINT)szSrc[j];
if(num <= 0x007f)//1 byte
{
szDest[i++] = num;
}
else if(num > 0x007f && num <= 0x000007ff)//2 bytes
{
szDest[i++] = 0xc0 + (0x1f & (num >> 6));//bigendian
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & num);
}
else if(num > 0x000007ff && num <= 0x0000ffff)//3 bytes
{
szDest[i++] = 0xe0 + (0x0f & (num >> 12));
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & (num >> 6));
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & num);
}
else if(num > 0x0000ffff && num <= 0x0010ffff)//4 bytes
{
szDest[i++] = 0xf0 + (0x07 & (num >> 18));
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & (num >> 12));
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & (num >> 6));
if(i >= nDest) break;
szDest[i++] = 0x80 + (0x3f & num);
}
if(i >= nDest) break;
}
return i;
}
int UTF8ToUnicode(const char* szSrc, int nSrc, wchar_t* szDest, int nDest)
{
int iIndex = 0, iLen = 0;
while(iIndex < nSrc && iLen <= nDest)
{
int i = 7, num;
while((szSrc[iIndex] >> i) & 1)
i--;
i < 7 ? i++ : i;
num = 8 - i;
switch(num)//bytes count
{
case 1:
szDest[iLen] = szSrc[iIndex];
break;
case 2:
szDest[iLen] = ((0x1f & szSrc[iIndex]) << 6) + (0x3f & szSrc[iIndex + 1]);//bigendian
break;
case 3:
szDest[iLen] = ((0x0f & szSrc[iIndex]) << 12) + ((0x3f & szSrc[iIndex + 1]) << 6) + (0x3f & szSrc[iIndex + 2]);
break;
case 4:
szDest[iLen] = ((0x0f & szSrc[iIndex]) << 18) + ((0x3f & szSrc[iIndex + 1]) << 12) + ((0x3f & szSrc[iIndex + 2]) << 6) + (0x3f & szSrc[iIndex + 3]);
break;
default:
break;
}
iIndex += num;
iLen++;
}
return iLen;
}