本文参考引用的其他博主的段落,均归其原创作者。

背景:在做网络通信的时候,总是会遇到各种样的编码格式问题,头疼不已,这次,为了一个中文的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. 题外话

  1. 这里就要说一下我一开始的问题了,最初的问题时在代码中,汉字字符串如何转为unicode码,以及如何从unicode码转为汉字,为什么和utf-8扯上关系了呢?(当时我也不太清楚),因为unicode是字符集,而utf-8才是用来显示的,所以结果上网一搜,都是转成0xXX这样的格式,这下彻底混乱了,我的数据是\uXXXX这样的,于是,一通乱搜。
  2. 现在终于对汉字,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编码互相转化的方法

  1. 使用libciconv库进行编解码
  2. 使用标准库函数提供的方法,提供了4个函数:wctomb,mbtowc,wcstombs,mbstowcs

10. 下面来逐个详细介绍。

  1. c语言利用iconv实现utf-8和unicode互转
  1. iconv是linux下的编码转换的工具,它提供命令行的使用和函数接口支持
  2. 在centos7的系统安装libciconv的支持环境

#yum search iconv

#yum install -y libticonv-devel.x86_64 libticonv.x86_64

  1. 使用iconv时,并不是拿来直接就能得出我们想要的结果,还需要根据不同的数据传输样式,进行一些处理封装,才能达到我们想要的效果(数据样式),我专门再做一篇根据各种样式的数据,封装的代码吧

链接:

11. c语言使用wcstombs实现utf-8和unicode互转尝试

  1. 为什么要叫尝试呢,因为我没有成功。。。
  2. wctomb,mbtowc,wcstombs,mbstowcs这四个函数的功能自行百度吧
  3. 使用这个函数,其中提到了宽字符和多字节的概念,于是大量的疑问诞生了

12. 什么是宽字符

用多个字节来代表的字符称之为宽字符。

13. 什么是多字节

一个汉字占3个字节,这种字符在C语言中称为多字节字符(Multibyte Character)。

14. 下面这个问题,可能是我的操作不对

使用wcstombs,根据函数介绍,将宽字符转成字节,汉字转出来的不是unicode码,却可以将unicode码转换为汉字,这里有两个问题,

  1. 将汉字转出来的是什么东西?
  2. 可以将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中宽字符多字节的解释:


应用示例:

http://www.360doc.com/content/17/0620/23/7991404_665016917.shtml

Ubuntu下实现UTF8编码转为Unicode编码 C程序


linux下c语言利用iconv函数实现utf-8转unicode


关于“为何Unicode中文字符占取2个字节,而 UTF-8却占3个字节”的网络解释修正:


Unicode码数据大端小端的判定