对于开发物联网或者跟网络相关的人员来说应对不同的编码转换尤其麻烦,如果所用的库有当然最好,对于单片机开发或者一些其他开发来说,库就相对少点或者不好找,所以就总结了一份来方便使用。
最近搞了一段时间联网的产品,因为需要连接服务器,而自己的系统用的编码是GBK的,所以数据编码方式会有所差异,需要我们自行转化编码来让系统可以理解传的数据的含义(包括自己)。
在网上找了很久相关的资料,GBk与Unicode,utf8之间是没有明确的转换公式,主流还是使用查表法来索引对应的编码。Unicode与utf8之间就存在对应的转换(工程使用vs搭建的,代码用C语言)
/*****************************************************************************
* 将一个字符的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,
int outSize)
{
//assert(pOutput != NULL);
//assert(outSize >= 6);
if (pOutput == NULL || outSize<6) return 0;
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;
}
/*****************************************************************************
* 将一个字符的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)
{
extern int enc_get_utf8_size(const unsigned char pInput);
//assert(pInput != NULL && Unic != NULL);
if (pInput == NULL || Unic == NULL) return 0;
// b1 表示UTF-8编码的pInput中的高字节, b2 表示次高字节, ...
char b1, b2, b3, b4, b5, b6;
*Unic = 0x0; // 把 *Unic 初始化为全零
int utfbytes = enc_get_utf8_size(*pInput);
unsigned char *pOutput = (unsigned char *)Unic;
switch (utfbytes)
{
关于GBK与Unicode,utf8区别
GBK对于单片机开发的应该不陌生,目前有几个版本,但是都是往下兼容,用的时候其实也没啥顾忌的。常用的是GB2312与GB18030,前者虽然收录的汉字不全(其实最新也未必全,毕竟每时每刻都有可能有新的汉字被收录),但是起码常用的都有,占用的空间也相对小很多,适合rom小的设备使用。后者就相对全很多,不用担心输入生僻字却显示了寂寞。在window上如果设置地区是中国或者语言是大陆的,编码其实都是GBK的编码。对于中文来说一个汉字占用2个字节。
Unicode相对国际化一点可以表示世界内所有文字(前提是收录进去了),最大4个字节代表一个字。我们常用的短信其实就是用Unicode编码的。对于中文来说一个汉字占用2个字节(大概)
utf-8是Unicode变种而来,可能因为好用吧,基本服务器跟浏览器都是使用utf-8替代以前的Unicode,可能还有一些没改,但是主流都是使用这个了,相信不久就全部都改成utf-8。所以基本我们使用的话都是将utf-8转成我们系统上所使用的编码。对于中文来说一个汉字占用3个字节
eg:对于英文及普通字符,所有编码都是一样的,都是占用一个字节 ,详细可以查看ASCII表?
分享一个网站?http://www.mytju.com/classCode/tools/encode_gb2312.asp
这个可以查看文字所对应的数据是怎样的
比如中文? ‘一’
对应GBK为????????0xD2BB
对应Unicode为? ? ? ? 0x4E00
对应utf-8为? ? ? ? 0xE4B880
关于GBK与Unicode,utf8互转,这里是使用查表法,首先都是GBK与Unicode之间相互转化,再进而转成utf8
WCHAR ff_convert ( /* Converted code, 0 means conversion error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
const WCHAR *p;
WCHAR c;
int i, n, li, hi;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to unicode */
p = oem2uni;
hi = sizeof oem2uni / 4 - 1;
} else { /* Unicode to OEM code */
p = uni2oem;
hi = sizeof uni2oem / 4 - 1;
}
li = 0;
for (n = 16; n; n--) {
i = li + (hi - li) / 2;
if (chr == p[i * 2]) break;
if (chr > p[i * 2])
li = i;
else
hi = i;
}
c = n ? p[i * 2 + 1] : 0;
}
return c;
}
其中 oem2uni与uni2oem就是对应的表
下面提供了自己整理的函数跟测试例子,大家可以按需求下载,都是一样的文件。转换有的是单个转换有的是整个数组一次性转的,使用的时候要看清楚。
免费共享通道
链接:https://pan.baidu.com/s/1dbX-_som28s61I4P_wzRBg? 提取码:i0g1
付费支持下载
https://download.csdn.net/download/qq_41851997/20979303
来源、参考、鸣谢(部分,还有忘了找不到,不代表最终来源)
https://www.amobbs.com/thread-4805076-1-1.html https://www.cnblogs.com/mickole/articles/3663924.html
cc936.c -- 正点原子
|