C++实现判断一个字符串是否为UTF8或GBK格式的方法

本文实例讲述了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;

 

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
在 Linux 系统下,可以使用 iconv 函数库将字符串编码从 UTF-8 转换为 GBK 编码。 具体的实现步骤如下: 1. 包含头文件 `#include <iconv.h>` 2. 定义 iconv_t 变量,用于存储转换句柄。 3. 调用 iconv_open 函数打开转换句柄。 4. 准备源字符串和目标字符串的缓冲区,以及它们的长度。 5. 调用 iconv 函数进行转换。 6. 关闭转换句柄。 7. 释放缓冲区。 下面是一个简单的示例代码: ```cpp #include <iostream> #include <iconv.h> #include <cstring> int main() { // 源字符串 const char* str_utf8 = u8"这是一段 UTF-8 编码字符串。"; // 转换句柄 iconv_t cd = iconv_open("GBK", "UTF-8"); if (cd == (iconv_t)-1) { perror("iconv_open"); return -1; } // 源字符串的长度和目标字符串的缓冲区 size_t len_utf8 = strlen(str_utf8); size_t len_gbk = len_utf8 * 2; // 预留足够的空间 char* str_gbk = new char[len_gbk]; // 进行转换 char* inbuf = const_cast<char*>(str_utf8); char* outbuf = str_gbk; size_t inlen = len_utf8; size_t outlen = len_gbk; if (iconv(cd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)-1) { perror("iconv"); iconv_close(cd); delete[] str_gbk; return -1; } // 输出结果 std::cout << "UTF-8 编码字符串:" << str_utf8 << std::endl; std::cout << "GBK 编码字符串:" << str_gbk << std::endl; // 关闭转换句柄并释放缓冲区 iconv_close(cd); delete[] str_gbk; return 0; } ``` 需要注意的是,在实际使用过程中,可能会遇到一些编码转换失败的情况,需要根据具体的错误码进行处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值