本文实例讲述了C++实现判断一个字符串是否为UTF8或GBK格式的方法。分享给大家供大家参考,具体如下:
在处理外部数据的时候,很可能因为数据格式不一样而导致乱码,甚至导致某些程序挂掉。鉴于对多数系统来说,使用是更被广泛使用的utf8,所以判断是不是utf8格式显得很重要了。
下面是一个判断字符串是否为utf8的函数:
bool is_str_utf8(const char* str)
{
unsigned int nBytes = 0;//UFT8可用1-6个字节编码,ASCII用一个字节
unsigned char chr = *str;
bool bAllAscii = true;
for (unsigned int i = 0; str[i] != '\0'; ++i){
chr = *(str + i);
//判断是否ASCII编码,如果不是,说明有可能是UTF8,ASCII用7位编码,最高位标记为0,0xxxxxxx
if (nBytes == 0 && (chr & 0x80) != 0){
bAllAscii = false;
}
if (nBytes == 0) {
//如果不是ASCII码,应该是多字节符,计算字节数
if (chr >= 0x80) {
if (chr >= 0xFC && chr <= 0xFD){
nBytes = 6;
}
else if (chr >= 0xF8){
nBytes = 5;
}
else if (chr >= 0xF0){
nBytes = 4;
}
else if (chr >= 0xE0){
nBytes = 3;
}
else if (chr >= 0xC0){
nBytes = 2;
}
else{
return false;
}
nBytes--;
}
}
else{
//多字节符的非首字节,应为 10xxxxxx
if ((chr & 0xC0) != 0x80){
return false;
}
//减到为零为止
nBytes--;
}
}
//违返UTF8编码规则
if (nBytes != 0) {
return false;
}
if (bAllAscii){ //如果全部都是ASCII, 也是UTF8
return true;
}
return true;
}
关于utf8的一般性简介和二进制格式可以参考百度百科。同样关于GBK的判断,也是使用的同样的方法,具体代码如下:
bool is_str_gbk(const char* str)
{
unsigned int nBytes = 0;//GBK可用1-2个字节编码,中文两个 ,英文一个
unsigned char chr = *str;
bool bAllAscii = true; //如果全部都是ASCII,
for (unsigned int i = 0; str[i] != '\0'; ++i){
chr = *(str + i);
if ((chr & 0x80) != 0 && nBytes == 0){// 判断是否ASCII编码,如果不是,说明有可能是GBK
bAllAscii = false;
}
if (nBytes == 0) {
if (chr >= 0x80) {
if (chr >= 0x81 && chr <= 0xFE){
nBytes = +2;
}
else{
return false;
}
nBytes--;
}
}
else{
if (chr < 0x40 || chr>0xFE){
return false;
}
nBytes--;
}//else end
}
if (nBytes != 0) { //违返规则
return false;
}
if (bAllAscii){ //如果全部都是ASCII, 也是GBK
return true;
}
return true;
}
按照编码规则这么写,是正确的。但鉴于现在的utf8对于中文一般都是三个字节,而且utf8的编码规则存在重合,如果是utf8,使用上面的这个函数,就会出现一个尴尬的问题,当中文字符为奇数个判断正确,为则偶数个无法区别。
使用MultiByteToWideChar转换UTF8为GBK(UTF8在Windows的代码页是CP_UTF8)
两个使用的函数:
1,UTF8转化为Unicode,inline为了编译后更快运行,老用到了,返回字符串为了使用链式表达式
inline WCHAR *UTF8ToUnicode(const char *str) throw()
{
int i = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,str,-1,NULL,0);
WCHAR *strUnicode=new WCHAR[i];
MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,str,-1,strUnicode,i);
return strUnicode;
delete []strUnicode;
}
一定要返回WCHAR 或wchar_t类型,否则有些字符就会变成“?”,Unicode(UCS-2)是2个字节宽
2,Unicode转化为UTF8,inline同上意义
inline char *UnicodeToUTF8(const WCHAR* pText) throw()
{
int i= WideCharToMultiByte(CP_UTF8,0,pText,-1,NULL,0,NULL,NULL); //输入缓冲区大小是宽字符数
char *strUTF8 = new char[i];
WideCharToMultiByte(CP_UTF8,0,pText,-1,strUTF8,i,NULL,NULL);
return strUTF8;
delete []strUTF8;
参考了网上一些方法:所谓的短字符,就是用8bit来表示的字符,典型的应用是ASCII码. 而宽字符,顾名思义,就是用16bit表示的字符,典型的有UNICODE.
常用的代码页有CP_ACP和CP_UTF8两个。
使用CP_ACP代码页就实现了ANSI与Unicode之间的转换。
使用CP_UTF8代码页就实现了UTF-8与Unicode之间的转换。
1. ASCII to Unicode(CP_ACP)
wstring ASCIIToUNICODE(char cArry[]) //传入参数为ANSI串,即用char数组或者string表示的串
{
int nLen = ::MultiByteToWideChar(CP_ACP, 0, cArry, -1, NULL, NULL); //将MultiByteToWideChar()的第四个形参设为-1,即可返回长度
wchar_t *pTemp = new wchar_t[nLen]; //new一个wchar_t空间,保存Unicode串
memset(pTemp, 0, nLen*sizeof(wchar_t));
::MultiByteToWideChar(CP_ACP, 0, cArry, -1, (LPWSTR)pTemp, nLen);
wstring str = pTemp;
if (pTemp)
{
delete [] pTemp;
pTemp = NULL;
}
return str;
}
2. Unicode to ASCII(CP_ACP)
string UNICODEToASCII(wchar_t cArry[]) //传入参数为Unicode串,用“wchar_t cArry[] = {L"这是个测试"};”表示
{
int nLen = ::WideCharToMultiByte(CP_ACP, 0, cArry, -1, NULL, 0, NULL, NULL);
char *pTemp = new char[nLen]; //new 一个char数组,保存ANSI串
memset(pTemp, 0, nLen);
::WideCharToMultiByte(CP_ACP, 0, cArry, -1, pTemp, nLen, NULL, NULL);
string str = pTemp;
if (pTemp)
{
delete [] pTemp;
pTemp = NULL;
}
return str;
}
3. UTF-8 to Unicode(CP_UTF8)
wstring UTF8ToUnicode( const string& str )
{
int unicodeLen = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0 );
wchar_t *pUnicode = new wchar_t[unicodeLen];
memset(pUnicode, 0, unicodeLen*sizeof(wchar_t));
::MultiByteToWideChar( CP_UTF8, 0, str.c_str(), -1, (LPWSTR)pUnicode, unicodeLen );
wstring rt = pUnicode;
if(pUnicode )
{
delete [] pUnicode ;
pUnicode = NULL;
}
return rt;
}
4. Unicode to UTF-8(CP_UTF8)
string UnicodeToUTF8( const wstring& str )
{
// wide char to multi char
int iTextLen = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, NULL, 0, NULL, NULL );
char *pElementText= new char[iTextLen];
memset(pElementText, 0, iTextLen);
::WideCharToMultiByte( CP_UTF8, 0, str.c_str(), -1, pElementText, iTextLen, NULL, NULL );
string strText;
strText = pElementText;
if(pElementText)
{
delete [] pElementText;
pElementText = NULL;
}
return strText;
}
}
void main()
{
char sBuf[25]={0};
strcpy(sBuf, "我最棒");
//获取输入缓存大小
int sBufSize=strlen(sBuf);
//获取输出缓存大小
//VC++ 默认使用ANSI,故取第一个参数为CP_ACP
DWORD dBufSize=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, NULL, 0);
printf("需要wchar_t%u个\n", dBufSize);
wchar_t * dBuf=new wchar_t[dBufSize];
wmemset(dBuf, 0, dBufSize);
//进行转换
int nRet=MultiByteToWideChar(CP_ACP, 0, sBuf, sBufSize, dBuf, dBufSize);
if(nRet<=0)
{
cout<<"转换失败"<<endl;
DWORD dwErr=GetLastError();
switch(dwErr)
{
case ERROR_INSUFFICIENT_BUFFER:
printf("ERROR_INSUFFICIENT_BUFFER\n");
break;
case ERROR_INVALID_FLAGS:
printf("ERROR_INVALID_FLAGS\n");
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER\n");
break;
case ERROR_NO_UNICODE_TRANSLATION:
printf("ERROR_NO_UNICODE_TRANSLATION\n");
break;
}
}
else
{
cout<<"转换成功"<<endl;
cout<<dBuf;
}
delete(dBuf);
}
//从宽字符串转换窄字符串
wchar_t sBuf[25]={0};
wcscpy(sBuf, L"我最棒");
//获取转换所需的目标缓存大小
DWORD dBufSize=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, NULL,0,NULL, FALSE);
//分配目标缓存
char *dBuf = new char[dBufSize];
memset(dBuf, 0, dBufSize);
//转换
int nRet=WideCharToMultiByte(CP_OEMCP, 0, sBuf, -1, dBuf, dBufSize, NULL, FALSE);
if(nRet<=0)
{
printf("转换失败\n");
}
else
{
printf("转换成功\nAfter Convert: %s\n", dBuf);
}
delete []dBuf;