概述

我们在单片机开发中常会遇到需要将UTF-8转换为GBK编码的需求。

在我们了解各种编码格式的情况下可知, UFT-8不能直接转成GBK,需中转成unicode再转换为gbk。而unicode和gbk之间没有算法可以直接计算,需要查表方式获取。

这个表有前辈已经整理好了,可直接使用。我们可以在相关资料中得到相关文件。

文件介绍

CC932.C  -->日本的Japanese Shift-JIS编码

CC936.C  -->Simplified Chinese GBK 编码

CC949.C  -->朝鲜的Korean EUC-KR编码

CC950.C  -->Traditional Chinese Big5编码

代码解读

const WCHAR uni2oem[]__attribute__((at(0x8005000)))= {
/*  Unicode - OEM,  Unicode - OEM,  Unicode - OEM,  Unicode - OEM */0x00A4, 0xA1E8, 0x00A7, 0xA1EC, 0x00A8, 0xA1A7, 0x00B0, 0xA1E3,0x00B1, 0xA1C0, 0x00B7, 0xA1A4, 0x00D7, 0xA1C1, 0x00E0, 0xA8A4,0x00E1, 0xA8A2, 0x00E8, 0xA8A8, 0x00E9, 0xA8A6, 0x00EA, 0xA8BA,

在CC936.C中我们发现有这两个数组,这两个数组则是Unicode和GBK之间的对应关系。

WCHAR ff_convert (   /* Converted code, 0 means conversion error */WCHAR chr,    /* Character code to be converted */UINT    dir     /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{const WCHAR *p;WCHAR c;int i, n, li, hi;if (chr < 0x80) {   /* ASCII */c = chr;} else {if (dir) {      /* OEMCP to unicode */p = oem2uni;hi = sizeof(oem2uni) / 4 - 1;  //除于4是因为4个字节为一组,所以除于4,减1是因为二分法原理} else {       /* Unicode to OEMCP */p = uni2oem;hi = sizeof(uni2oem) / 4 - 1;}li = 0;for (n = 16; n; n--) {  //循环16次的原因是2^16次方一定能够找到i = li + (hi - li) / 2;if (chr == p[i * 2]) break; // p[i * 2]原因是:0、2、4...才是unicode数据if (chr > p[i * 2])li = i;elsehi = i;}c = n ? p[i * 2 + 1] : 0; //后一个字节则为gbk码数据}return c;
}

ff_convert()函数通过二分查找法,通过二分查找法能够完成,Unicode和gbk编码的相互转换。但是这两个数组会很大,所以在单片机中一般需存在外部存储器,如flash中。

如何在单片机上完成,UTF-8转GBK呢?

  1. 我们可以借助工具将CC936.C编码的数组转成BIN文件存入flash中。
  2. 把UTF-8转换成unicode码
  3. 根据二分法查找,找到对应的gbk码。

UTF-8与unicode的相互转换函数如下:

int enc_get_utf8_size(const unsigned char pInput){unsigned char c = pInput;// 0xxxxxxx 返回0// 10xxxxxx 不存在// 110xxxxx 返回2// 1110xxxx 返回3// 11110xxx 返回4// 111110xx 返回5// 1111110x 返回6if(c< 0x80) return 0;if(c>=0x80 && c<0xC0) return -1;if(c>=0xC0 && c<0xE0) return 2;if(c>=0xE0 && c<0xF0) return 3;if(c>=0xF0 && c<0xF8) return 4;if(c>=0xF8 && c<0xFC) return 5;if(c>=0xFC) return 6;}/* 将一个字符的UTF8编码转换成Unicode(UCS-2和UCS-4)编码. * * 参数: *    pInput      指向输入缓冲区, 以UTF-8编码 *    Unic        指向输出缓冲区, 其保存的数据即是Unicode编码值, *                类型为unsigned long . * * 返回值: *    成功则返回该字符的UTF8编码所占用的字节数; 失败则返回0. * * 注意: *     1. UTF8没有字节序问题, 但是Unicode有字节序要求; *        字节序分为大端(Big Endian)和小端(Little Endian)两种; *        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位) ****************************************************************************/
int enc_utf8_to_unicode_one(const unsigned char* pInput, unsigned long *Unic)
{  // b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...  char b1, b2, b3, b4, b5, b6;  int utfbytes; unsigned char *pOutput;  *Unic = 0x00; // 把 *Unic 初始化为全零  pOutput = (unsigned char *)Unic;utfbytes= enc_get_utf8_size(*pInput);  //先得到UTF-8的长度switch ( utfbytes )  {  case 0:  *pOutput     = *pInput;  utfbytes    += 1;  break;  case 2:  b1 = *pInput;  b2 = *(pInput + 1);  if ( (b2 & 0xE0) != 0x80 )  return 0;  *pOutput     = (b1 << 6) + (b2 & 0x3F);  *(pOutput+1) = (b1 >> 2) & 0x07;  break;  case 3:  b1 = *pInput;  b2 = *(pInput + 1);  b3 = *(pInput + 2);  if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80) )  return 0;  *pOutput     = (b2 << 6) + (b3 & 0x3F);  *(pOutput+1) = (b1 << 4) + ((b2 >> 2) & 0x0F);  break;  case 4:  b1 = *pInput;  b2 = *(pInput + 1);  b3 = *(pInput + 2);  b4 = *(pInput + 3);  if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)  || ((b4 & 0xC0) != 0x80) )  return 0;  *pOutput     = (b3 << 6) + (b4 & 0x3F);  *(pOutput+1) = (b2 << 4) + ((b3 >> 2) & 0x0F);  *(pOutput+2) = ((b1 << 2) & 0x1C)  + ((b2 >> 4) & 0x03);  break;  case 5:  b1 = *pInput;  b2 = *(pInput + 1);  b3 = *(pInput + 2);  b4 = *(pInput + 3);  b5 = *(pInput + 4);  if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)  || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80) )  return 0;  *pOutput     = (b4 << 6) + (b5 & 0x3F);  *(pOutput+1) = (b3 << 4) + ((b4 >> 2) & 0x0F);  *(pOutput+2) = (b2 << 2) + ((b3 >> 4) & 0x03);  *(pOutput+3) = (b1 << 6);  break;  case 6:  b1 = *pInput;  b2 = *(pInput + 1);  b3 = *(pInput + 2);  b4 = *(pInput + 3);  b5 = *(pInput + 4);  b6 = *(pInput + 5);  if ( ((b2 & 0xC0) != 0x80) || ((b3 & 0xC0) != 0x80)  || ((b4 & 0xC0) != 0x80) || ((b5 & 0xC0) != 0x80)  || ((b6 & 0xC0) != 0x80) )  return 0;  *pOutput     = (b5 << 6) + (b6 & 0x3F);  *(pOutput+1) = (b5 << 4) + ((b6 >> 2) & 0x0F);  *(pOutput+2) = (b3 << 2) + ((b4 >> 4) & 0x03);  *(pOutput+3) = ((b1 << 6) & 0x40) + (b2 & 0x3F);  break;  default:  return 0;  break;  }  return utfbytes;
}  /***************************************************************************** * 将一个字符的Unicode(UCS-2和UCS-4)编码转换成UTF-8编码. * * 参数: *    unic     字符的Unicode编码值 *    pOutput  指向输出的用于存储UTF8编码值的缓冲区的指针 *    outsize  pOutput缓冲的大小 * * 返回值: *    返回转换后的字符的UTF8编码所占的字节数, 如果出错则返回 0 . * * 注意: *     1. UTF8没有字节序问题, 但是Unicode有字节序要求; *        字节序分为大端(Big Endian)和小端(Little Endian)两种; *        在Intel处理器中采用小端法表示, 在此采用小端法表示. (低地址存低位) *     2. 请保证 pOutput 缓冲区有最少有 6 字节的空间大小! ****************************************************************************/
int enc_unicode_to_utf8_one(unsigned long unic, unsigned char *pOutput)
{  if ( unic <= 0x0000007F )  {  // * U-00000000 - U-0000007F:  0xxxxxxx  *pOutput     = (unic & 0x7F);  return 1;  }  else if ( unic >= 0x00000080 && unic <= 0x000007FF )  {  // * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  *(pOutput+1) = (unic & 0x3F) | 0x80;  *pOutput     = ((unic >> 6) & 0x1F) | 0xC0;  return 2;  }  else if ( unic >= 0x00000800 && unic <= 0x0000FFFF )  {  // * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  *(pOutput+2) = (unic & 0x3F) | 0x80;  *(pOutput+1) = ((unic >>  6) & 0x3F) | 0x80;  *pOutput     = ((unic >> 12) & 0x0F) | 0xE0;  return 3;  }  else if ( unic >= 0x00010000 && unic <= 0x001FFFFF )  {  // * U-00010000 - U-001FFFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  *(pOutput+3) = (unic & 0x3F) | 0x80;  *(pOutput+2) = ((unic >>  6) & 0x3F) | 0x80;  *(pOutput+1) = ((unic >> 12) & 0x3F) | 0x80;  *pOutput     = ((unic >> 18) & 0x07) | 0xF0;  return 4;  }  else if ( unic >= 0x00200000 && unic <= 0x03FFFFFF )  {  // * U-00200000 - U-03FFFFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  *(pOutput+4) = (unic & 0x3F) | 0x80;  *(pOutput+3) = ((unic >>  6) & 0x3F) | 0x80;  *(pOutput+2) = ((unic >> 12) & 0x3F) | 0x80;  *(pOutput+1) = ((unic >> 18) & 0x3F) | 0x80;  *pOutput     = ((unic >> 24) & 0x03) | 0xF8;  return 5;  }  else if ( unic >= 0x04000000 && unic <= 0x7FFFFFFF )  {  // * U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  *(pOutput+5) = (unic & 0x3F) | 0x80;  *(pOutput+4) = ((unic >>  6) & 0x3F) | 0x80;  *(pOutput+3) = ((unic >> 12) & 0x3F) | 0x80;  *(pOutput+2) = ((unic >> 18) & 0x3F) | 0x80;  *(pOutput+1) = ((unic >> 24) & 0x3F) | 0x80;  *pOutput     = ((unic >> 30) & 0x01) | 0xFC;  return 6;  }  return 0;
}

单片机中读取外部flash中的转换表完成转换,函数如下:

WCHAR ff_convert (   /* Converted code, 0 means conversion error */WCHAR src,    /* Character code to be converted */UINT    dir     /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{WCHAR t[2];WCHAR c;u32 i, li, hi;u16 n;             u32 gbk2uni_offset=0;       if (src < 0x80)c = src;//ASCII,直接不用转换.else {if(dir)   //GBK 2 UNICODE{gbk2uni_offset=ftinfo.ugbksize/2;    //得到数据的偏移地址,双向转换的两个数组在一起}else  //UNICODE 2 GBK  {   gbk2uni_offset=0; }    /* Unicode to OEMCP */hi=ftinfo.ugbksize/2;//对半开.hi =hi / 4 - 1;li = 0;for (n = 16; n; n--){i = li + (hi - li) / 2;  W25QXX_Read((u8*)&t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出4个字节  if (src == t[0]) break;if (src > t[0])li = i;  else hi = i;    }c = n ? t[1] : 0;         }return c;
}          

单片机中UTF-8如何转换得到GBK编码相关推荐

  1. mysql gbk编码 字节数,mysql中utf-8编码数据库转换成GBK编码的问题

    摘要 腾兴网为您分享:mysql中utf-8编码数据库转换成GBK编码的问题,之了课堂,易信,一折包邮,星球联盟等软件知识,以及七日杀,草莓软件,装修施工站,桔子会,桌面切换,看小说神器,酷派应用商店 ...

  2. Python:UTF-8编码转换成GBK编码

    2019独角兽企业重金招聘Python工程师标准>>> #!/usr/bin/env python # -*- coding:utf-8 -*- #UTF-8转换成GBK编码 #te ...

  3. python声明编码为gbk_python入门:UTF-8转换成GBK编码

    1 #!/usr/bin/env python 2 #-*- coding:utf-8 -*- 3 #UTF-8转换成GBK编码 4 #temp(临时雇员,译音:泰坡) 5 #decode(编码,译音 ...

  4. C#编写Rtf文档,中文与字母区分,C#将汉字转换成GBK编码

    最近两天在调试仰邦的LED双色屏.他们用的控制卡只能支持三种自定义传参方式,一.文本传值,二.Rtf文档传值,三.bmp图片传值.第一种第三种在仓库中传值无法做到.其主要原因是传的数据比较的多.对于R ...

  5. AVR单片机中ATmega8的AD转换探究

    AD采集最好要满足的条件:采样频率不小于被采集信号最高频率的两倍,则采样输出信号就可以无失真的重新啊还原输入信号,通常的实际应用中,采样频率为采集最高频率的5-10倍. AD芯片的数据输出方式有串行和 ...

  6. linux 字符集转换命令,Linux下GBK编码到UTF-8文件编码转换方法

    Linux命令行下查看看文件的编码 enca 文件名 Linux文件名编码批量转换 convmv -f 源编码 -t 新编码 [选项] 文件名 常用参数: -r 递归处理子文件夹 --notest 真 ...

  7. C#怎么将GBK编码转换成UTF-8编码?

    C#怎么将GBK编码转换成UTF-8编码? private void ChangeEncode(Encoding fromCoding,Encoding toCoding,string fileNam ...

  8. python中的进制转换以及浮点数二进制转换

    为什么要注意这三点: 1.首先是项目中用到的进制转换,常用的int ord hex 以及编写的转换函数,作为记录 2.其次是python 3相对于旧版主要的区别就在这里,主要是bytes 和 stri ...

  9. android utf-8 转 gbk编码,【字符编码系列】GBK,UTF-8,UTF-16之间的转换

    写在前面的话 本文属于 字符编码系列文章之一,更多请前往 字符编码系列. 大纲 不同编码转换的理论基础 UTF-16转UTF-8 UTF-16转GBK UTF-16和UTF-8之间的转换 UTF-16 ...

最新文章

  1. 区块链还可以这么玩?“点亮莫高窟”背后的腾讯云区块链
  2. block为什么用copy以及如何解决循环引用
  3. plsql连接不上64位oracle,plsql develope连接64位Oracle 11g出错解决方案(图)
  4. 算法学习:后缀自动机
  5. 2.2.1 静态成员
  6. 学用 ASP.Net 之 System.Char 结构
  7. 大连a货翡翠,东莞a货翡翠
  8. linux 卸载kde,Ubuntu KDE终端系统安装与卸载
  9. 回溯算法团灭子集、排列、组合问题
  10. java 配置文件 路径问题_java 配置文件的路径问题
  11. java 子进程id,Java程序如何获得自己的进程ID?
  12. python之_init_函数的简介
  13. IDL | 实验三、IDL编程演练
  14. 关于ubuntu下无线网卡经常连不上网络的问题
  15. 父与子的编程之旅 python 3_python3-父与子的编程之旅第十五章
  16. python员工信息管理_用Python实现职工信息管理系统
  17. java数组排序的方法_Java数组排序方法详解
  18. IADS Revision Note 1: Asymptotic Notations
  19. 如何编译 cm12 (for 一加手机)
  20. html设置文字超过字数_CSS限制字数,超出部份显示点点点...

热门文章

  1. java 泛型枚举_java枚举泛型
  2. android wifi flow
  3. css_color配色
  4. VOLTE语音时延问题定位
  5. Web App的未来
  6. 慢动作视频不能播放问题
  7. 英特尔第十代处理器为什么不支持win7_不支持win7的cpu 七代cpu为什么不支持win7?...
  8. Linux whereis、find和locate命令找不到文件
  9. 客户关系管理核心理念
  10. Javascript实现商品秒杀倒计时(时间与服务器时间同步)