本文主要是介绍UTF8转UCS——被微软折磨的日子,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
前段时间搞协议,遇到些编码的问题,非英文的字符一直传输失败。搞得还以为开发者不支持中文,还给大佬发了个邮件,Is there any plan to support non-English?。大佬一直没回我,不知道是感觉我问的太傻X了还是没看到我的邮件。
研究了下协议传递非英文字符的问题,这个协议必须把字符串以utf8格式传进去,然后这个协议将utf8编码转换成UCS2,再通过网络发出去。
在windows下开一个dos窗口,chcp 65001切换成utf8。中文输入还是不行,转换ucs2失败。顺便研究了一下utf8和UCS2编码。
同样的程序,在linux下命令行输入就可以转换ucs2,难道是windows命令行通过chcp 65001转换后,传到程序的还不是utf8?事实证明,确实这样,windows dos命令行切换utf8后,显示的可以是utf8,但是输入的还不是。好了,让c#去调用吧,转换成utf8的byte[]数组后喂给它,问题解决,完美。
提供一个c下的utf8、ucs编码互转的代码。请移步我的github,移植自某开源协议:https://github.com/wangzhhbj/some-c-tools/tree/master/Transcoding
UTF8
UTF,是UnicodeTransformation Format的缩写,意为Unicode转换格式。
UTF-8是UNICODE的一种变长字符编码,UTF-8用1到6个字节编码UNICODE字符。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。
如表:
1字节 0xxxxxxx
2字节 110xxxxx 10xxxxxx
3字节 1110xxxx 10xxxxxx 10xxxxxx
4字节 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
5字节 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
6字节 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与UNICODE编码是一一对应的,位高低顺序也相同。
实际将UNICODE转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。
因此那些基本ASCII字符集中的字符(UNICODE兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。
Unicode - UCS - 万国码
通用字符集 - UCS(Universal Character Set)
UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。
UCS-2对每一个Unicode码位使用2bytes字集(16位bit);
UCS-4对每一个Unicode码位使用4bytes字集(32位bit);
UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不能支持在UTF-16中超过2bytes的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。
UTF-32 原本是 UCS-4 的子集,但JTC1/SC2/WG2声明,所有未来对字符的指定都将会限制在BMP及其14个补充平面。于是就现状而言,除了 UTF-32 标准包含额外的 Unicode 意涵,UCS-4 和 UTF-32 大体是相同的。
转换
UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:
UCS-2编码(16进制) | UTF-8 字节流(二进制) |
---|---|
0000 - 007F | 0xxxxxxx |
0080 - 07FF | 110xxxxx 10xxxxxx |
0800 - FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
关键函数
直接上代码,完整请移步github,移植自某开源协议:https://github.com/wangzhhbj/some-c-tools/tree/master/Transcoding
/**---------------------------------------------------* ucs2 : UTF8* utf32 1 Bytes 0xxxxxxx * utf32 2 Bytes 110xxxxx 10xxxxxx * utf32 3 Bytes 1110xxxx 10xxxxxx 10xxxxxx * utf32 4 Bytes 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
static int
utf8toutf32(const unsigned char **pp, uint32_t *out)
{const unsigned char *p = *pp;unsigned c = *p;if (c & 0x80) // c & 0b10000000,返回值非0表明是超过1个字节的编码{if ((c & 0xE0) == 0xC0) // 2字节编码场景,(c & 0b11100000)==0b11000000,符合 110xxxxx {const unsigned c2 = *++p; // 判断下一个字节,符合10xxxxxx if ((c2 & 0xC0) == 0x80) // (c2 & 0b11000000)==0b10000000 {*out = ((c & 0x1F) << 6) | (c2 & 0x3F);} else // 不符合110xxxxx 10xxxxxx {return WIND_ERR_INVALID_UTF8;}} else if ((c & 0xF0) == 0xE0) //3字节场景 (c & 0b11110000)==0b11100000,满足1110xxxx{const unsigned c2 = *++p;if ((c2 & 0xC0) == 0x80) //判断下一字节 (c2 & 0b11000000)==0b10000000,满足10xxxxxx{const unsigned c3 = *++p;if ((c3 & 0xC0) == 0x80) //判断下一字节 (c3 & 0b11000000)==0b10000000,满足10xxxxxx{*out = ((c & 0x0F) << 12)| ((c2 & 0x3F) << 6)| (c3 & 0x3F);} else {return WIND_ERR_INVALID_UTF8;}} else {return WIND_ERR_INVALID_UTF8;}} else if ((c & 0xF8) == 0xF0) // (c & 0b11111000)==0b11110000 4字节场景{const unsigned c2 = *++p;if ((c2 & 0xC0) == 0x80) // 3字节, (c2 & 0b11000000)==0b10000000,满足10xxxxxx{const unsigned c3 = *++p;if ((c3 & 0xC0) == 0x80) // 2字节, (c2 & 0b11000000)==0b10000000,满足10xxxxxx{const unsigned c4 = *++p;if ((c4 & 0xC0) == 0x80) // 1字节, (c2 & 0b11000000)==0b10000000,满足10xxxxxx{*out = ((c & 0x07) << 18)| ((c2 & 0x3F) << 12)| ((c3 & 0x3F) << 6)| (c4 & 0x3F);} else {return WIND_ERR_INVALID_UTF8;}} else {return WIND_ERR_INVALID_UTF8;}} else {return WIND_ERR_INVALID_UTF8;}} else {return WIND_ERR_INVALID_UTF8;}} else {*out = c; //单个字节场景}*pp = p;return 0;
}
参考资料
《请问UTF-8与UCS-2之间有何区别与联系》https://www.zhihu.com/question/302200063/answer/530692688
《搞懂编码 GBK 和 UTF8》https://www.zhihu.com/question/302200063/answer/530692688
《软件中的字符串编码, UCS2, UTF8哪个更优》https://www.zhihu.com/question/346965173/answer/832323946
《UTF8和UCS2》https://blog.csdn.net/a13935302660/article/details/77507809
这篇关于UTF8转UCS——被微软折磨的日子的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!