现在的位置: 首页 > 综合 > 正文

gbk/utf8/unicode编码转换,不依赖任何系统API自己实现与平台无关的转换算法

2012年11月11日 ⁄ 综合 ⁄ 共 3671字 ⁄ 字号 评论关闭

原文链接(http://blog.csdn.net/coollofty/article/details/8058859)

GBK、UTF8、Unicode,这三种编码是一般程序开发,或者各种应用中最常见的三种编码方式了,还不知道基本概念的赶快请教搜索引擎自己科普一下。

本文的目的不是来讲述什么是GBK编码,什么是UTF8编码,他们的编码规则是怎样的这一类的基本概念的文章。本文要讲述的是如何没有系统API辅助的情况下,如何最简单的快速实现这三种编码之间的转换。也许你会说,这有什么意义呢?Windows上、Linux上,我们都有系统API可以进行转换,一个API搞定了。退一步说,还有libiconv可以垫底,何必自己搞?话是这么说没错,但这不等于所有的系统上都有这些编码转换的API,比如Android的NDK开发的时候,编码转换就是一个讨厌的问题,虽然Android自身有带这样的API,但是他没有提供给我们使用,网上的解决方案都存在着或多或少的问题,不是性能不成(通过Java转调,效率太低),就是自己去dl_open
icu库,但是那个函数的名称又很蛋疼。而我们只是需要转换这么3种觉编码而已,搞出iconv来一下就是好几MB的库,真觉得没有必要。总之解决得都很不爽。咱是C++程序员,索性,本着底层开发的原则,自己搞一套吧。

这三种编码的转换,UTF8与Unicode之间是很简单的(这里的Unicode指的是UCS-2),直接贴代码:

  1. //参数1是UTF8字符串当前位置指针,这里必须要是指针,因为必须要通过第1个字符进行判断才知道一个完整的字符的编码要向后取多少个字符  
  2. //参数2是返回的UCS-2编码的Unicode字符  
  3. inline int UTF82UnicodeOne(const char* utf8, wchar_t& wch)  
  4. {  
  5.     //首字符的Ascii码大于0xC0才需要向后判断,否则,就肯定是单个ANSI字符了  
  6.     unsigned char firstCh = utf8[0];  
  7.     if (firstCh >= 0xC0)  
  8.     {  
  9.         //根据首字符的高位判断这是几个字母的UTF8编码  
  10.         int afters, code;  
  11.         if ((firstCh & 0xE0) == 0xC0)  
  12.         {  
  13.             afters = 2;  
  14.             code = firstCh & 0x1F;  
  15.         }  
  16.         else if ((firstCh & 0xF0) == 0xE0)  
  17.         {  
  18.             afters = 3;  
  19.             code = firstCh & 0xF;  
  20.         }  
  21.         else if ((firstCh & 0xF8) == 0xF0)  
  22.         {  
  23.             afters = 4;  
  24.             code = firstCh & 0x7;  
  25.         }  
  26.         else if ((firstCh & 0xFC) == 0xF8)  
  27.         {  
  28.             afters = 5;  
  29.             code = firstCh & 0x3;  
  30.         }  
  31.         else if ((firstCh & 0xFE) == 0xFC)  
  32.         {  
  33.             afters = 6;  
  34.             code = firstCh & 0x1;  
  35.         }  
  36.         else  
  37.         {  
  38.             wch = firstCh;  
  39.             return 1;  
  40.         }  
  41.   
  42.         //知道了字节数量之后,还需要向后检查一下,如果检查失败,就简单的认为此UTF8编码有问题,或者不是UTF8编码,于是当成一个ANSI来返回处理  
  43.         for(int k = 1; k < afters; ++ k)  
  44.         {  
  45.             if ((utf8[k] & 0xC0) != 0x80)  
  46.             {  
  47.                 //判断失败,不符合UTF8编码的规则,直接当成一个ANSI字符返回  
  48.                 wch = firstCh;  
  49.                 return 1;  
  50.             }  
  51.   
  52.             code <<= 6;  
  53.             code |= (unsigned char)utf8[k] & 0x3F;  
  54.         }  
  55.   
  56.         wch = code;  
  57.         return afters;  
  58.     }  
  59.     else  
  60.     {  
  61.         wch = firstCh;  
  62.     }  
  63.   
  64.     return 1;  
  65. }  

有了这个函数,那么转换一整个UTF8字符串,就是很简单的一件事情了,下面直接给出了最短的实现:

  1. //参数1是UTF8编码的字符串  
  2. //参数2是输出的UCS-2的Unicode字符串  
  3. //参数3是参数1字符串的长度  
  4. //使用的时候需要注意参数2所指向的内存块足够用。其实安全的办法是判断一下pUniBuf是否为NULL,如果为NULL则只统计输出长度不写pUniBuf,这样  
  5. //通过两次函数调用就可以计算出实际所需要的Unicode缓存输出长度。当然,更简单的思路是:无论如何转换,UTF8的字符数量不可能比Unicode少,所  
  6. //以可以简单的按照sizeof(wchar_t) * utf8Leng来分配pUniBuf的内存……  
  7. int UTF82Unicode(const char* utf8Buf, wchar_t *pUniBuf, int utf8Leng)  
  8. {     
  9.     int i = 0, count = 0;  
  10.     while(i < utf8Leng)  
  11.     {  
  12.         i += UTF82UnicodeOne(utf8Buf + i, pUniBuf[count]);  
  13.         count ++;  
  14.     }  
  15.   
  16.     return count;  
  17. }  


搞定了UTF-8转Unicode之后,反过来搞定Unicode转UTF8也是很容易的,下面直接给出单个Unicode转UTF8编码的函数:

  1. inline int Unicode2UTF8(unsigned wchar, char *utf8)  
  2. {  
  3.     int len = 0;  
  4.     if (wchar < 0xC0)  
  5.     {   
  6.         utf8[len ++] = (char)wchar;  
  7.     }  
  8.     else if (wchar < 0x800)  
  9.     {  
  10.         utf8[len ++] = 0xc0 | (wchar >> 6);  
  11.         utf8[len ++] = 0x80 | (wchar & 0x3f);  
  12.     }  
  13.     else if (wchar < 0x10000)  
  14.     {  
  15.         utf8[len ++] = 0xe0 | (wchar >> 12);  
  16.         utf8[len ++] = 0x80 | ((wchar >> 6) & 0x3f);  
  17.         utf8[len ++] = 0x80 | (wchar & 0x3f);  
  18.     }  
  19.     else if (wchar < 0x200000)   
  20.     {  
  21.         utf8[len ++] = 0xf0 | ((int)wchar >> 18);  
  22.         utf8[len ++] = 0x80 | ((wchar >> 12) & 0x3f);  
  23.         utf8[len ++] = 0x80 | ((wchar >> 6) & 0x3f);  
  24.         utf8[len ++] = 0x80 | (wchar & 0x3f);  
  25.     }  
  26.     else if (wchar < 0x4000000)  
  27.     {  

抱歉!评论已关闭.