首页 >> 大全

UTF8转UCS——被微软折磨的日子

2023-11-01 大全 29 作者:考证青年

前言

前段时间搞协议,遇到些编码的问题,非英文的字符一直传输失败。搞得还以为开发者不支持中文,还给大佬发了个邮件,Is there any plan to non-?。大佬一直没回我,不知道是感觉我问的太傻X了还是没看到我的邮件。

研究了下协议传递非英文字符的问题,这个协议必须把字符串以utf8格式传进去,然后这个协议将utf8编码转换成UCS2,再通过网络发出去。

在下开一个dos窗口,chcp 65001切换成utf8。中文输入还是不行,转换ucs2失败。顺便研究了一下utf8和UCS2编码。

同样的程序,在linux下命令行输入就可以转换ucs2,难道是命令行通过chcp 65001转换后,传到程序的还不是utf8?事实证明,确实这样, dos命令行切换utf8后,显示的可以是utf8,但是输入的还不是。好了,让c#去调用吧,转换成utf8的byte[]数组后喂给它,问题解决,完美。

提供一个c下的utf8、ucs编码互转的代码。请移步我的,移植自某开源协议:

UTF8

UTF,是n 的缩写,意为转换格式。

UTF-8是的一种变长字符编码,UTF-8用1到6个字节编码字符。对于某一个字符的UTF-8编码,如果只有一个字节则其最高二进制位为0;如果是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了其编码的位数,其余各字节均以10开头。UTF-8最多可用到6个字节。

如表:

1字节

2字节

3字节

4字节

5字节

6字节

因此UTF-8中可以用来表示字符编码的实际位数最多有31位,即上表中x所表示的位。除去那些控制位(每字节开头的10等),这些x表示的位与编码是一一对应的,位高低顺序也相同。

实际将转换为UTF-8编码时应先去除高位0,然后根据所剩编码的位数决定所需最小的UTF-8编码位数。

因此那些基本ASCII字符集中的字符(兼容ASCII)只需要一个字节的UTF-8编码(7个二进制位)便可以表示。

- UCS - 万国码

通用字符集 - UCS( Set)

UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。

UCS-2对每一个码位使用字集(16位bit);

UCS-4对每一个码位使用字集(32位bit);

UTF-16可看成是UCS-2的父集。在没有辅助平面字符( code )前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。现在若有软件声称自己支持UCS-2编码,那其实是暗指它不能支持在UTF-16中超过的字集。对于小于的UCS码,UTF-16编码就等于UCS码。

UTF-32 原本是 UCS-4 的子集,但JTC1/SC2/WG2声明,所有未来对字符的指定都将会限制在BMP及其14个补充平面。于是就现状而言,除了 UTF-32 标准包含额外的 意涵,UCS-4 和 UTF-32 大体是相同的。

转换

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

UCS-2编码(16进制)UTF-8 字节流(二进制)

UTF8转UCS——被微软折磨的日子_UTF8转UCS——被微软折磨的日子_

0000 - 007F

0080 - 07FF

0800 - FFFF

关键函数

直接上代码,完整请移步,移植自某开源协议:

/**---------------------------------------------------* 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之间有何区别与联系》

《搞懂编码 GBK 和 UTF8》

《软件中的字符串编码, UCS2, UTF8哪个更优》

《UTF8和UCS2》

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了