首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

字符编码 Unicode UTF-8,GB2312,shift-jis编码判断


字符串编码判断;Unicode,UTF-8之间编码
2008-07-18 10:11
Unicode和UTF-8之间编码的区别Unicode是一个字符集,而UTF-8是Unicode的其中一种,Unicode是定长的都为双字节,而UTF-8是可变的,对于汉字来说Unicode占有的字节比UTF-8占用的字节少1个字节Unicode为双字节,而UTF-8中汉字占三个字节
                        Basic Multilingual Plane)字符最多只用到3字节长下面看一下UTF-8编码表:

       U-00000000 - U-0000007F: 0xxxxxxx
        U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
        U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
        U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    xxx 的位置由字符编码数的二进制表示的位填入, 越靠右的 x 具有越少的特殊意义,只用最短的那个足够表达一个字符编码数的多字节串 注意在多字节串中, 第一个字节的开头"1"的数目就是整个串中字节的数目而第一行中以0开头,是为了兼容ASCII编码,为一个字节,第二行就为双字节字符串,第三行为3字节,如汉字就属于这种,以此类推(其实我们可以简单的把前面的1的个数看成字节数)
                        
    为了要将Unicode转换为UTF-8,当然要知道他们的区别到底在什么地方下面来看一下,在Unicode中的编码是怎样转换成UTF-8的,在UTF-8中,如果一个字符的字节小于0x80(128)则为ASCII字符,占一个字节,可以不用转换,因为UTF-8兼容ASCII编码假如在Unicode中汉字你的编码为u4F60,把它转换为二进制为100111101100000,然后按照UTF-8的方法进行转换可以将Unicode二进制从地位往高位取出二进制数字,每次取6位,如上述的二进制就可以分别取出为如下所示的格式,前面按格式填补,不足8位用0填补


      
       unicode: 100111101100000                  4F60

           utf-8:    11100100,10111101,10100000       E4BDA0

    从上面就可以很直观的看出Unicode到UTF-8之间的转换,当然知道了UTF-8的格式后,就可以进行逆运算,就是按照格式把它在二进制中的相应位置上取出,然后在转换就是所得到的Unicode字符了(这个运算可以通过位移来完成)
                     
    如上述的你的转换,由于其值大于0x800小于0x10000,因此可以判断为三字节存储,则最高位需要向右移12位再根据三字节格式的最高位为11100000(0xE0)求或(|)就可以得到最高位的值了同理第二位则是右移6位,则还剩下最高位和第二位的二进制值,可以通过与111111(0x3F)求按位于(&)操作,再和11000000(0x80)求或(|)第三位就不用移位了,只要直接取最后六位(与111111(ox3F)取&),在与11000000(0x80)求或(|)OK了,转换成功!在VC++中的代码如下所示(Unicode到UTF-8的转换)


        1const wchar_t pUnicode = L"你";
        2char utf8[3+1];
        3memset(utf8,0,4);
        4 utf8[0] =0xE0|(pUnicode>>12);
        5 utf8[1] =0x80|((pUnicode>>6)&0x3F);
        6 utf8[2] =0x80|(pUnicode&0x3F);
        7utf8[3] ="\0";
        8//char[4]就是UTF-8的字符你了

    当然在UTF-8到Unicode的转换也是通过移位等来完成的,就是把UTF-8那些格式相应的位置的二进制数给揪出来在上述例子中你为三个字节,因此要每个字节进行处理,有高位到低位进行处理在UTF-8中你为11100100,10111101,10100000从高位起即第一个字节11100100就是把其中的"0100"给取出来,这个很简单只要和11111(0x1F)取与(&),由三字节可以得知最到位肯定位于12位之前,因为每次取六位所以还要将得到的结果左移12位,最高位也就这样完成了0100,000000,000000而第二位则是要把111101给取出来,则只需将第二字节10111101和111111(0x3F)取与(&)在将所得到的结果左移6位与最高字节所得的结果取或(|),第二位就这样完成了,得到的结果为0100,111101,000000以此类推最后一位直接与111111(0x3F)取与(&),再与前面所得的结果取或(|)即可得到结果0100,111101,100000OK,转换成功!在VC++中的代码如下所示(UTF-8到Unicode的转换)


    1//UTF-8格式的字符串
    2constchar* utf8 ="你";
    3wchar_t unicode;
    4unicode = (utf8[0] &0x1F) <<12;
    5unicode |= (utf8[1] &0x3F) <<6;
    6unicode |= (utf8[2] &0x3F);
    7//unicode is ok!
                           
至于Unicode的转换为GB2312在MFC中Windows有自带的API(WideCharToMultiByte)可以转换这样也就能够将UTF-8格式转换为GB2312了,

美妙的C++代码
4 char[0] = 0xE0|(pUnicode>>12);
5 char[1] = 0x80|((pUnicode>>6)&0x3F);
6 char[2] = 0x80|(pUnicode&0x3F);
7 char[3] = "\0";

#ifdef WIN32
/************************************************************************
* Name : ASCII2UTF8()
* Desc : 将acii字符串转换为utf8格式; 返回转换后的长度
************************************************************************/
static int ASCII2UTF8(
const char* szBuf     //原字符串缓冲区
, std::string& szDest    //目标字符串
);
/************************************************************************
* Name : UTF82ACII()
* Desc : UTF8格式转换为ASCII格式字符串
************************************************************************/
static int UTF82ASCII(
const char* szUtf8Data   //原字符串缓冲区
, std::string& szDest   //目标字符串
);
//-------------------------------------------------------
// 判断是否Utf8
//-------------------------------------------------------
static bool IsUTF8( const char * pzInfo );
//-------------------------------------------------------
// 判断是否gb2312
//-------------------------------------------------------
static bool IsGB2312( const char *pzInfo );
#endif
//-------------------------------------------------------
// 是否gb2312
//-------------------------------------------------------
static int IsGB( char *pText );
//-------------------------------------------------------
// 是否有中文
//-------------------------------------------------------
static bool IsChinese( const char *pzInfo );
//.cpp
#ifdef WIN32
/***************************************************
* Function:       ASCII2UTF8
* Description:    Ascii转换为uft-8
* Input:          szBuf:原字符串缓冲区
                  szDest:utf-8目标
* Output:        
* Return:        
* Others:        
***************************************************/
int CGTDBSVRLib::ASCII2UTF8(
      const char* szBuf     //原字符串缓冲区
      , std::string& szDest
      )
{
int nLen = 0;
#define W_LEN 1024
#define BUF_MAX (W_LEN *4)
try
{
WCHAR wChar[W_LEN] = { 0 };
char szDestData[BUF_MAX] = { 0 };
MultiByteToWideChar(CP_ACP, 0, szBuf, -1, wChar, sizeof(wChar)/sizeof(wChar[0]));
nLen = WideCharToMultiByte(CP_UTF8, 0, wChar, -1, szDestData, sizeof(szDestData), NULL, NULL);
szDest = szDestData;
#ifdef _DEBUG_TEST
char szBuf[BUF_MAX] = { 0 };
MultiByteToWideChar(CP_UTF8, 0, szUtf8Data, nLen +1, wChar, sizeof(wChar)/sizeof(wChar[0]));
nLen = WideCharToMultiByte(CP_ACP, 0, wChar, -1, szBuf, sizeof(szBuf), NULL, NULL);
GT_TRACE(e_Debug, "\r\nsizeof(wChar) = %ld", sizeof(wChar));
#endif
}
catch (long nLine)
{
// GT_TRACE(e_Debug, "\r\n 代码异常%s: LINE = %ld\n", __FILE__, nLine);
}
catch (...)
{
}
return nLen;
}
/***************************************************
* Function:       UTF82ASCII
* Description:    utf-8转换为Ascii
* Input:          szUtf8Data:原字符串缓冲区
                  szDest:Ascii目标字符
* Output:        
* Return:        
* Others:        
***************************************************/
int CGTDBSVRLib::UTF82ASCII(
      const char* szUtf8Data   //原字符串缓冲区
      , std::string& szDest
      )
{
int nLen = 0;
#define W_LEN 1024
#define BUF_MAX (W_LEN *4)
WCHAR wChar[W_LEN] = { 0 };
char szDestData[BUF_MAX] = { 0 };
MultiByteToWideChar(CP_UTF8, 0, szUtf8Data, -1, wChar, sizeof(wChar)/sizeof(wChar[0]));
nLen = WideCharToMultiByte(CP_ACP , 0, wChar, -1, szDestData, sizeof(szDestData), NULL, NULL);
szDest = szDestData;
return nLen;
}
/***************************************************
* Function:       IsUTF8
* Description:    判断是否utf-8编码字符
* Input:          pzInfo:要判断的字符
* Output:        
* Return:        
* Others:        
***************************************************/
bool CGTDBSVRLib::IsUTF8( const char * pzInfo )
{
int nWSize = MultiByteToWideChar( CP_UTF8,MB_ERR_INVALID_CHARS,pzInfo,-1,NULL,0 );
int error = GetLastError();
if (error == ERROR_NO_UNICODE_TRANSLATION)
{
return false;
}
//判断是否是gb2312,只要把CP_UTF8用936代替即可.
return true;
}
/***************************************************
* Function:       IsGB2312
* Description:    判断是否gb2312编码字符
* Input:          pzInfo:待判断字符
* Output:        
* Return:        
* Others:        
***************************************************/
bool CGTDBSVRLib::IsGB2312( const char *pzInfo )
{
int nWSize = MultiByteToWideChar( 936,MB_ERR_INVALID_CHARS,pzInfo,-1,NULL,0 );
int error = GetLastError();
if (error == ERROR_NO_UNICODE_TRANSLATION)
{
return false;
}
//判断是否是CP_UTF8,只要把936用CP_UTF8代替即可.
return true;
}
#endif
/***************************************************
* Function:       IsGB
* Description:    是否gb2312
* Input:          pText:待判断字符
* Output:        
* Return:        
* Others:        
***************************************************/
int CGTDBSVRLib::IsGB( char *pText )
{
unsigned char *sqChar = (unsigned char *)pText;
if (sqChar[0] >= 0xa1)
{
if (sqChar[0] == 0xa3)
{
   return 1;//全角字符
}
else
{
   return 2;//汉字
}
}
else
{
return 0;//英文、数字、英文标点
}
}

/***************************************************
* Function:       IsChinese
* Description:    是否有中文
* Input:          pzInfo:待判断字符
* Output:        
* Return:        
* Others:        
***************************************************/
bool CGTDBSVRLib::IsChinese( const char *pzInfo )
{
int i;
char *pText = (char*)pzInfo;
while (*pText != '\0')
{
i = IsGB(pText);
switch(i)
{
case 0:
   pText++;
   break;
case 1:
   pText++;
   pText++;
   break;
case 2:
   pText++;
   pText++;
   return TRUE;
   break;
}
}
return false;


以上编码可能存在问题,使用时候请进行修改。

[wangjy17908]
添加时间:2009-09-29
版权所有(C)2005-2015