原住址:http://www.cnitblog.com/wujian-IT/archive/2007/12/13/37671.html    

      /*      author:   wu.jian   (吴剑)      English name: Sword

      /*      date:      2007-12-13

      /*      purpose:   知识共享



      这几天工作上碰到了UTF-8转GB2312的问题,而且是在嵌入式的环境下,没有API可用,查了很多网上的资料,大多调用VC或者Linux下自带的接口。在这里我将这两天的工作做个总结。

      总的来说分为两大步(这里就不介绍基础知识了):



      一、UTF8 -> Unicode

      由于UTF8和Unicode存在着联系,所以不需要任何库就可以直接进行转换。首先要看懂UTF8的编码格式:

      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  

      前面几个1就代表后面几个字节是属于一起的。如果要解析一长串UTF8格式的字符串,这点就很有用了。下面这个函数就是判断前面几个1的(这里有define APP_PRINT printf,这样当release的时候将这个宏定义为空就行了,不需要一个一个去改,又方便重新调试):

      int GetUtf8ByteNumForWord(u8 firstCh)  //判断前面几个1

      {

          u8 temp = 0x80;

          int num = 0;

 

          while (temp & firstCh)

          {

                num++;

                 temp = (temp >> 1);

           }

APP_PRINT("the num is: %d", num);

        return num;

      }

      利用这个函数可以得到字符串中那几个字节是一起的。因为UTF8最大只有6个字节,所以就根据返回值来处理这里我只处理了3个字节和1个字节的UTF8的编码,因为一般来说中文在UTF8中是3个字节



//将len个字节的UTF8格式的转换成GB2312格式存放在temp预先申请好的缓冲区中

void Utf8ToGb2312(const char* utf8, int len, char *temp)

{

       APP_PRINT("utf8->unicode: \n");

       APP_PRINT("utf8: [");

       for (int k = 0; k < len; k++)

       {

              APP_PRINT("%02x ", utf8[k]);

       }

       APP_PRINT("]\n");

 

       int byteCount = 0;

       int i = 0;

       int j = 0;



       u16 unicodeKey = 0;

       u16 gbKey = 0;





      //循环解析

       while (i < len)

       {   

        switch(GetUtf8ByteNumForWord((u8)utf8[i]))

        {

          case 0:

                temp[j] = utf8[i];

                byteCount = 1;

          break;



          case 2:

          temp[j] = utf8[i];

          temp[j + 1] = utf8[i + 1];

          byteCount = 2;

          break;



         case 3:

                 //这里就开始进行UTF8->Unicode

                 temp[j + 1] = ((utf8[i] & 0x0F) << 4) | ((utf8[i + 1] >> 2) & 0x0F);

                 temp[j] = ((utf8[i + 1] & 0x03) << 6) + (utf8[i + 2] & 0x3F);



                //取得Unicode的值

                 memcpy(&unicodeKey, (temp + j), 2);

                 APP_PRINT("unicode key is: 0x%04X\n", unicodeKey);



                  //根据这个值查表取得对应的GB2312的值

                gbKey = SearchCodeTable(unicodeKey);

                APP_PRINT("gb2312 key is: 0x%04X\n", gbKey);

    

                if (gbKey != 0)

                {

                       //here change the byte

                        //不为0表示搜索到,将高低两个字节调换调成我要的形式

                       gbKey = (gbKey >> 8) | (gbKey << 8);

                       APP_PRINT("after changing, gb2312 key is: 0x%04X\n", gbKey);

                       memcpy((temp + j), &gbKey, 2);

                  }

                byteCount = 3;

          break;



          case 4:

          byteCount = 4;

          break;

         case 5:

          byteCount = 5;

          break;

         case 6:

          byteCount = 6;

          break;

    

         default:

          APP_PRINT("the len is more than 6\n");

          break;    

        }

i += byteCount;

        if (byteCount == 1)

        {

               j++;

        }

        else

        {

               j += 2;

        }

  

       }

       APP_PRINT("utf8: [");

       for (k = 0; k < j; k++)

       {

              APP_PRINT("%02x ", temp[k]);

       }

       APP_PRINT("]\n");

}



      二、下面主要谈谈利用查表法来进行Unicode->GB2312的转换,首先下载码表,一般码表都是将GB2312的放在前面,Unicode放在后面,这样对于我们来说不方便使用,所以我转换了下,将Unicode放在前面,而且按照从小到大排好序。(这里只需要考虑都为两个字节的情况,因为前面的UTF8->Unicode并没有将单字节的ASCII转换成Unicode)

            (1)做表:(可以到这里下载:http://blog.91bs.com/?action=show&id=20,这里谢谢渣渣的猪窝)

            这个是原来的样子:

            0x8140 0x4E02 #CJK UNIFIED IDEOGRAPH

            0x8141 0x4E04 #CJK UNIFIED IDEOGRAPH

            0x8142 0x4E05 #CJK UNIFIED IDEOGRAPH

            先弄成(这个可以写个小程序来做,我就是在VC上做的,如果需要可以联系我):

            { 0x4E02 ,0x8140 }, //CJK UNIFIED IDEOGRAPH

            { 0x4E04 ,0x8141 }, //CJK UNIFIED IDEOGRAPH

            { 0x4E05 ,0x8142 }, //CJK UNIFIED IDEOGRAPH

            这样就可以把这些放在.h文件中了,下面是我的定义:

            typedef struct unicode_gb

            {

                   unsigned short unicode;

                   unsigned short gb;

            } UNICODE_GB;

UNICODE_GB code_table[] = 

            {

                  { 0x4E02, 0x8140 },   //CJK UNIFIED IDEOGRAPH

                  { 0x4E04, 0x8141 },  //CJK UNIFIED IDEOGRAPH

                  { 0x4E05, 0x8142 },  //CJK UNIFIED IDEOGRAPH

                  。。。。。。省略



            下面这一步也很简单,在VC中用冒泡排序法,对这个数组按照unicode值进行排序,如果需要可以联系我,把最终结果打印出来,在cmd下运行name > 1.txt就输出到文件,这样就有了一个按照unicode排好序的unicode->gb2312码表。



   int main(int argc, char *argv[])

{

int num = 0;

    UNICODE_GB temp;

    int i = 0;

    int j = 0;

num = sizeof(code_table) / sizeof(UNICODE_GB);

printf("struct size: %d | total size: %d | num is: %d \n", 

    sizeof(UNICODE_GB), sizeof(code_table), num);

for (i = 0; i < num; i++)

    {

        for (j = 1; j < num - i; j++)

        {

            if (code_table[j - 1].unicode > code_table[j].unicode)

            {

                temp.unicode = code_table[j - 1].unicode;

                temp.gb = code_table[j - 1].gb;

                code_table[j - 1].unicode = code_table[j].unicode;

                code_table[j - 1].gb = code_table[j].gb;

                code_table[j].unicode = temp.unicode;

                code_table[j].gb = temp.gb;

            }

        }

    }

printf("here is the code table sorted by unicode\n\n");

for (i = 0; i < num; i++)

    {

        printf("{\t0x%04X,\t0x%04X\t},\t\n", code_table[i].unicode, code_table[i].gb);

     }

printf("\n\n print over!\n");



   //以下注释掉的其实就是我用来对原来的码表添加,{,}等用的

   /*

    char buff[100];

    char buff_1[100]; 

 

    FILE* fp = NULL;

    FILE *fp_1 = NULL;

memset(buff, 0, 100);

    memset(buff_1, 0, 100);

 

    fp = fopen("table.txt", "rw");

    fp_1 = fopen("table_1.txt", "a+");

if ((fp == NULL) || (fp_1 == NULL))

    {

        printf("open file error!\n");

        return 1;

    }

while (fgets(buff, 100, fp) != NULL)

    {

        buff[8] = ',';

fputs(buff, fp_1);

    }

 */

return 0;

}



      最后就是搜索算法了,前面已经排好序了,现在我们把排好序的码表放在我们真正需要的.h文件中。大家应该猜我用什么算法搜索了吧,二分法。



#define CODE_TABLE_SIZE 21791

//这个表是死的,所以就直接用宏表示长度,不用每次都用size,不过这样可能对移植性不好。

u16 SearchCodeTable(u16 unicodeKey)

{

    int first = 0;

    int end = CODE_TABLE_SIZE - 1;

    int mid = 0;

while (first <= end)

    {

        mid = (first + end) / 2;

if (code_table[mid].unicode == unicodeKey)

        {

            return code_table[mid].gb;

        }

        else if (code_table[mid].unicode > unicodeKey)

        {

            end = mid - 1;

        }

        else 

        {

            first = mid + 1;

        }

    }

    return 0;

}

      到此,已经能够将UTF8串转换成GB2312了。是一长串哦,而不是单个汉字的编码转换。

UTF-8, Unicode, GB2312格式串转换之C语言版的更多相关文章

  1. 7、UTF-8, Unicode, GB2312格式串转换之C语言版

    (申明:此文章属于原创,若转载请表明作者和原处链接 )            /*      author:   wu.jian    (吴剑)      English name: Sword    ...

  2. ASP:GB2312格式文本文件转换成UTF-8格式

    '-------------------------------------------------'函数名称:gb2utf_file'作用:利用AdoDb.Stream对象来把GB2312格式文本文 ...

  3. UNICODE串转换成char类型串的四种方法

    1. 调用 WideCharToMultiByte() API int WideCharToMultiByte (     UINT    CodePage,                //1 U ...

  4. 各种编码中汉字所占字节数;中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030

    vim settings set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936,latin1set termencoding=utf-8se ...

  5. 中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030

    中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030 cp936是微软自己发布的用在文件系统中的编码方式.而bg2312是中国国家标准.我明白mount -t vfa ...

  6. 创建文件夹并解决解决unicode和ASCII码转换的问题

    # -*- coding: UTF-8 -*-import sysimport timeimport os #解决unicode和ASCII码转换的问题reload(sys) #解决unicode和A ...

  7. Unicode编码解码在线转换工具

    // Unicode编码解码在线转换工具 Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standar ...

  8. [转] 将DOS格式文本文件转换成UNIX格式

    点击此处阅读原文 用途说明 dos2unix命令用来将DOS格式的文本文件转换成UNIX格式的(DOS/MAC to UNIX text file format converter).DOS下的文本文 ...

  9. 将形如:Oct 8, 2016 5:29:44 PM串转换成正常时间在真机上遇到的坑

    将形如:Oct 8, 2016 5:29:44 PM串转换成正常时间在真机上遇到的坑 /** * 根据传入字符串 * * @param str 传入的日期字符串 形如:Oct 8, 2016 5:29 ...

随机推荐

  1. Sublime 输入中文显示方框问号乱码

     最近使用的sublime 编辑器出现了打开写好的程序,中文显示的确是方框,方框里面是问号,就是不显示中文.     然后再网上查找了一下,大概都是说是需要中文编码插件,比如converttoutf8 ...

  2. 1.mysql导论

    虽然之前用过mysql一年多,但大多只是会用,深入了解的不多.所以想利用平时时间 系统的总结总结. 一.什么是数据库:(数据库软件)     1).什么是数据库(软件):数据库(DB:DataBase ...

  3. 【P2158】仪仗队&欧拉函数详解

    来一道数论题吧. 这个题一眼看上去思路明确,应该是数论,但是推导公式的时候却出了问题,根本看不出来有什么规律.看了马佬题解明白了这么个规律貌似叫做欧拉函数,于是就去百度学习了一下这东西. 欧拉函数的含 ...

  4. HDFS存档

    Hadoop存档 每个文件均按块方式存储,每个块的元数据存储在namenode的内存中,因此Hadoop存储小文件会非常低效.因为大量的小文件会耗尽namenode中的大部分内存.存储小文件所需的磁盘 ...

  5. 修改SpringBoot 默认的小叶子图标

    Springboot 项目,在浏览器中访问时,浏览器上导航栏的图标是一片绿色的叶子,我们可以修改它. 将格式为.ico的图片放入以下任一项目文件夹即可.但,图片命名必须为favicon.ico 1.类 ...

  6. openstack Neutron分析(3)—— neutron-dhcp-agent源码分析

    1.neutron dhcp3个主要部件分别为什么?2.dhcp模块包含哪些内容?3.Dnsmasq配置文件是如何创建和更新的?4.DHCP agent的信息存放在neutron数据库的哪个表中? 扩 ...

  7. JavaScript 全部介绍

     1.new 表达式  new之后写函数名的话,就会把该函数作为构造函数来进行调用.   2.字符串型的运算  由于JavaScript的字符串型是不可变类型,所以字符串值本质上是不能改变的.这个答案 ...

  8. CSS3中的变形功能

    一.变形主要值得是利用transform功能来实现文字或图片的旋转,缩放,倾斜,移动这四种处理. 1.旋转-----transform:rotate(xxdeg);( IE9以上,safari 3.1 ...

  9. java多线程学习一

    声明:本篇博客是本人为了自己学习保存的心得,其内容主要是从大神——五月的仓颉的博客中学习而来,在此多谢大神五月的仓颉的分享,敬礼! 第一章:进程和线程的概念 进程:进程是操作系统中作为分配资源的基本单 ...

  10. js抛物线

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...