本文参考引用的其他博主的段落,均归其原创作者。
背景:在做网络通信的时候,总是会遇到各种样的编码格式问题,头疼不已,这次,为了一个中文的unicode转utf-8而头疼了两天,算是弄懂了其中的一部分理解吧。
首先我们要区分清楚很多概念,才不至于迷惑,才能理清楚这个问题,否则,我的脑袋就是一团浆糊。
1. 什么是utf-8?
UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码。(摘自百度百科)
2. 什么是unicode?
Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。
Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。随着计算机工作能力的增强,Unicode也在面世以来的十多年里得到普及。
目前的用于实用的 Unicode 版本对应于 UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。汉字也使用2个字节。
utf-8长度是1-6个字节,第一个字节的高位1的数目指明了这个utf-8的字符使用的byte数目,在UTF-8编码集中,每个汉字使用 3个字符表示
3. Unicode和utf-8的关系?
UTF-8 是 Unicode 的实现方式之一。
4. Utf-8的编码规则:
UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
下表总结了编码规则,字母x表示可用编码的位。
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
5. 汉字和utf-8的转换算法关系
紧接着4的内容,下面举个例子:
下面,还是以汉字严为例,演示如何实现 UTF-8 编码。
严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。
6. Utf-8和unicode的转换算法关系
到了这里,我脑袋糊住了,愣是纠结了好久,而且也脱离了我一开始的问题初衷。其实很简单,仔细看上面第5点内容,发现了什么?3个字节utf-8码就是基于unicode码换算来的啊,再反向换算回去不就是他们的互换规则码?真是傻逼了。
7. 题外话
- 这里就要说一下我一开始的问题了,最初的问题时在代码中,汉字字符串如何转为unicode码,以及如何从unicode码转为汉字,为什么和utf-8扯上关系了呢?(当时我也不太清楚),因为unicode是字符集,而utf-8才是用来显示的,所以结果上网一搜,都是转成0xXX这样的格式,这下彻底混乱了,我的数据是\uXXXX这样的,于是,一通乱搜。
- 现在终于对汉字,unicode,utf-8有了一点清晰的认识,但是总觉的还是隔着一层纱,他们之间的关系是
汉字---(通过编码,获取)------unicode------(通过解码,得到)--------utf-8
1个汉字 2字节 3字节
这里纠结了好久,我已经想不起来纠结什么了,结论就是:unicode解码后得到的3个字节信息,显示出来,他就是那一个汉字,所以,将通信信息里面收到的unicode数据,做解码之后,就是还原汉字了,真吐血。
3. 或许这些问题都很初级,也很幼稚,至少再大神看来,而且因为这个问题,我也被同事喷的不轻(向同事道歉,做我同事,难为您了),但我就是不懂啊,之前从来没有关注过,只有到用的时候,才回去关注他的机理。
8. Unicode的大端,小端的问题
Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。
如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式
9. 基于以上的了解,提供两种unicode和utf-8编码互相转化的方法
- 使用libciconv库进行编解码
- 使用标准库函数提供的方法,提供了4个函数:wctomb,mbtowc,wcstombs,mbstowcs
10. 下面来逐个详细介绍。
- c语言利用iconv实现utf-8和unicode互转
- iconv是linux下的编码转换的工具,它提供命令行的使用和函数接口支持
- 在centos7的系统安装libciconv的支持环境
#yum search iconv
#yum install -y libticonv-devel.x86_64 libticonv.x86_64
-
- 使用iconv时,并不是拿来直接就能得出我们想要的结果,还需要根据不同的数据传输样式,进行一些处理封装,才能达到我们想要的效果(数据样式),我专门再做一篇根据各种样式的数据,封装的代码吧
链接:
11. c语言使用wcstombs实现utf-8和unicode互转尝试
- 为什么要叫尝试呢,因为我没有成功。。。
- wctomb,mbtowc,wcstombs,mbstowcs这四个函数的功能自行百度吧
- 使用这个函数,其中提到了宽字符和多字节的概念,于是大量的疑问诞生了
12. 什么是宽字符
用多个字节来代表的字符称之为宽字符。
13. 什么是多字节
一个汉字占3个字节,这种字符在C语言中称为多字节字符(Multibyte Character)。
14. 下面这个问题,可能是我的操作不对
使用wcstombs,根据函数介绍,将宽字符转成字节,汉字转出来的不是unicode码,却可以将unicode码转换为汉字,这里有两个问题,
- 将汉字转出来的是什么东西?
- 可以将unicode码转换为汉字,那么,将汉字转换为其他的编码是什么编码?(按照原理上来讲,转出来的多字节就是utf-8的字节啊)
欢迎大家补充答案,给我解惑,谢谢!
参考以下链接:
Wctomb
https://www.runoob.com/cprogramming/c-function-wctomb.html
mbtowc
https://www.runoob.com/cprogramming/c-function-mbtowc.html
wcstombs
https://www.runoob.com/cprogramming/c-function-wcstombs.html
mbstowcs
https://www.runoob.com/cprogramming/c-function-mbstowcs.html
c中宽字符多字节的解释:
https://www.cnblogs.com/ymy124/archive/2012/03/23/2414992.html
应用示例:
http://www.360doc.com/content/17/0620/23/7991404_665016917.shtml
Ubuntu下实现UTF8编码转为Unicode编码 C程序
https://blog.csdn.net/xingkong886/article/details/54971191
linux下c语言利用iconv函数实现utf-8转unicode
https://www.cnblogs.com/etangyushan/p/3753847.html
关于“为何Unicode中文字符占取2个字节,而 UTF-8却占3个字节”的网络解释修正:
https://www.cnblogs.com/deepblue775737449/p/7604738.html
Unicode码数据大端小端的判定: