原住址: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了。是一长串哦,而不是单个汉字的编码转换。

转载于:https://www.cnblogs.com/alan666/p/8311940.html

UTF-8, Unicode, GB2312格式串转换之C语言版相关推荐

  1. utf8转gb2312 c语言,UTF-8, Unicode, GB2312格式串转换之C语言版

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

  2. 以串结构存储c语言版,数据结构C语言版 串的块链存储表示和实现

    <数据结构C语言版 串的块链存储表示和实现>由会员分享,可在线阅读,更多相关<数据结构C语言版 串的块链存储表示和实现(13页珍藏版)>请在人人文库网上搜索. 1.*数据结构C ...

  3. UTF-8,Unicode,GB2312编码转换(C语言)

    UTF-8,Unicode,GB2312编码转换(C语言) 最近在做MQTT客户端的时候,遇到需要将输入的GB2312中文转换为UTF8的问题,这边做一个整理. UTF-8转GB2312 代码: /* ...

  4. linux unicode 转换工具,字符集之间转换(UTF-8,UNICODE,Gb2312)

    特搜集了UTF-8,UNICODE,Gb2312他们3个之间的相互转换. UTF-8:   3字节一个字符 UNICODE: 2字节一个字符 GB2312:  1字节一个字符 例子: "你& ...

  5. C语言进制的格式字符,GB汉字文件转换成C语言Unicode十六进制字符串格式

    可以用在编程环境只能用GB,但程序中的汉字字符串需要用C语言的Unicode十六进制字符串格式表示.可以先在字符串中直接输入汉字,再用此程序转换. 源代码用C# //ascii & GB to ...

  6. html utf 8编码转换器,utf8和gb2312编码在线转换工具

    utf8和gb2312编码在线转换工具_网页代码站(www.webdm.cn) style="Z-INDEX: 1000; VISIBILITY: hidden; WIDTH: 1px; P ...

  7. UNICODE与UTF-8的转换详解

    UNICODE与UTF-8的转换详解 1 编码 在计算机中,各种信息都是以二进制编码的形式存在的,也就是说,不管是文字.图形.声音.动画,还是电影等各种信息,在计算机中都是以0和1组成的二进制代码表示 ...

  8. UNICODE与 UTF-8的转换详解

    1 编码 在计算机中,各种信息都是以二进制编码的形式存在的,也就是说,不管是文字.图形.声音.动画,还是电影等各种信息,在计算机中都是以0和1组成的二进制代码表示的.为了区分这些信息,人们就为计算机设 ...

  9. UNICODE与 UTF8的转换详解

    转载请注明出处: http://www.ins1000.cn/KnowledgeActionForReader?action=read&id=104 源文件下载地址:UTF- 8的转换详解(W ...

最新文章

  1. Git学习记录(一)
  2. 某快手程序员爆料:给小厂随便投投简历,面试表现很差也能过,大厂背书确实有用!...
  3. 前端JS调用微信扫一扫二维码
  4. C/C++中的NULL讨论和总结
  5. 大油井隐藏的箱子_魔兽世界:历经版本变迁的5大隐藏boss!全部都经历过的才是大神...
  6. 【水滴石穿】imooc_gp
  7. flex平均分布换行后自动对齐
  8. 控件(View)之TextSwitcher, Gallery, ImageSwitcher, GridView, ListView, ExpandableList【转】
  9. jar 、war、ear_在命令行上操作JAR,WAR和EAR
  10. 比特币的缺陷以及改进
  11. emr系统 php,完整电子病历系统c#源码
  12. Hibernate Native SQL查询示例
  13. TCP、UDP及IP协议总结
  14. 中国替代运动器材市场趋势报告、技术动态创新及市场预测
  15. java+线程安全的hash,多线程下HashMap安全问题-ConcurrentHashMap解析
  16. WPF:window设置单一开启
  17. CentOS hping3安装和应用
  18. 吴恩达深度学习课后作业-目标检测的环境配置
  19. UTC(世界标准时间)/GMT(格林威治时间)/CST(北京时间)
  20. IT男潘加宇:老婆在孩子班级群里怒怼数学老师

热门文章

  1. 追洞小组 | Jdbc反序列化漏洞复现浅析
  2. Python基于python实现的http+json协议接口自动化测试框架源码(实用改进版)
  3. Pycharm超使用快捷键
  4. pandas使用get_dummies进行one-hot编码
  5. Scala入门到精通——第十八节 隐式转换与隐式参数(一)
  6. ElasticSearch5.3插件开发(一)控制台打印信息
  7. 结合电商支付业务一文搞懂DDD
  8. 如何在Java应用里集成Spark MLlib训练好的模型做预测
  9. python全栈开发 * 08知识点汇总 * 180608
  10. 面向对象的三大特性————继承,多态