原住址: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. php 当前时间计算操作

    首先要设置时间为中国时区 date_default_timezone_set('PRC'); 对于获取当前时间戳后的各种时间计算 数据库保存最好用时间戳 当前时间time() 上一天 echo dat ...

  2. Codeforces Round #386 (Div. 2) C D E G

    一场比较简单的题 比较脑洞 C 如果坐车比较快的话 先走不如等车 所以最后的ans是min(纯走路,纯坐车) 讨论一下坐车时间 D 因为k一定是>=1的 所以当a=b的时候 GBGBGB这样间隔 ...

  3. JavaScript -- 控制table的创建 与 删除, 排序, 表格颜色

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 在物理机安装CentOS6.5

    这两天就要开始在用户的新服务器上部署生产环境了.之前一直都是在服务器上搭虚拟机,而在物理机上安装还是第一次. 首先是要准备启动程序.我用的U盘作为启动盘. 刻盘的操作参考 http://jingyan ...

  5. git 里面遇到的问题

    第一步:建立git仓库(本地) cd到你的本地项目根目录下,执行git命令 git init 第二步:将项目的所有文件添加到仓库中 git add . 如果想添加某个特定的文件,只需把.换成特定的文件 ...

  6. SQL Server 中WITH (NOLOCK)浅析(转)

    概念介绍  开发人员喜欢在SQL脚本中使用WITH(NOLOCK), WITH(NOLOCK)其实是表提示(table_hint)中的一种.它等同于 READUNCOMMITTED . 具体的功能作用 ...

  7. Linux命令之awk_1

    简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再 ...

  8. wpf多程序集之间共享资源字典--CLR名称空间未定义云云

    wpf多程序集之间共享资源字典--CLR名称空间未定义云云 分类: WPF 2012-10-28 10:57 1162人阅读 评论(0) 收藏 举报 以下介绍如何创建可用于在多个程序集之间共享的资源字 ...

  9. FunnelWeb 开源Blog引擎介绍

    FunnelWeb is an open source blog engine, built by developers for developers. Instead of fancy quotes ...

  10. 从AD域获取用户AD信息

    public static Dictionary<string, string> SearchADInfo(string adName) { string strTemp = " ...