关于Unicode编码的闲谈

来源:互联网 发布:中国海洋大学就业 知乎 编辑:程序博客网 时间:2024/06/07 22:03

发现网上关于编码的文章挺多,但是说的彻底清楚的基本没有,所以还是得自己来总结,毕竟每个人的基础不一样,所以只有每个人自己总结的才能透彻的理解。

关于unicode

大家都知道unicode又叫统一码、万国码。可以百科一下unicode的定义:

Unicode是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

... 只用2个字节就可以编码地球上几乎所有地区的文字。因此,创建了UNICODE编码。

注意上说的是2个字节可以编码“几乎”所有地区的文字,所以并不是世界上所有的字符都能用2个字节来编码,因此就有了UCS-2与UCS-4.

下面解释一下UCS-2与UCS-4

UCS:通用字符集(Universal Character Set)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。

Unicode 是基于UCS的标准来发展,并且同时也以书本的形式对外发表.

UCS-2用两个字节编码unicode,UCS-4用4个字节编码unicode。


弄清Unicode 与UTF的关系:

1,Unicode是世界上所有字符的一个集合,世界上的每个字符都有一个唯一的unicode编码数值,Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符.

2,UTF是表示对Unicode的编码方式,通俗的说就是对Unicode的存储方式。

一般常用的有这么几种编码:

UTF-8, UTF-16, UTF-32

3,Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。


下面看看UTF-8

UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下: 

Unicode编码(16进制) 
UTF-8 字节流(二进制)
000000 - 00007F 
0xxxxxxx
000080 - 0007FF 
110xxxxx 10xxxxxx
000800 - 00FFFF 
1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF 
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同,使用1个字节。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。


总结:世界上所有的字符都能够用unicode来表示Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符。

那么如果一个字符的编码是unicode的最大值0x10FFFF(21位),那么最少需要3个字节来表示这个字符。

长久以来,Unicode在我心中的概念就是:使用2个字节来编码字符,可以表示世界上所有的字符。但这种理解是错误的!

网上很多对unicode的定义里面说的:“ 只用2个字节就可以编码地球上几乎所有地区的文字”,是很蛋疼的一句话。虽然没错,但是很容易让新手产生误解,以为2个字节就可以表示所有的unicode编码了。很明显,至少要3个字节才能表示完unicode(世界上所有字符)。


UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。都是对unicode的编码方案。

例如,“汉” 的unicode对应的数字是0x6c49,而编码的程序数据是:
BYTE data_utf8[] = {0xE6, 0xB1, 0x89}; // UTF-8编码  3个字节表示“汉”这个字
WORD data_utf16[] = {0x6c49}; // UTF-16编码  2个字节表示“汉”这个字
DWORD data_utf32[] = {0x6c49}; // UTF-32编码  4个字节表示“汉”这个字

 Unicode最初被设计出来的时候希望使用2个字节就可以表示世界上的所有字符。因此,实现Unicode最直接的想法就是用两个字节来存储一个字符,如果大家都这么想就好了,这样一个字符就可以用2个字节长的短整形来存储,但是

1个字符=2个字节在现实中却遇到了麻烦。一方面,用2个字节表示一个字符,浪费了大量的空间(如果仅仅用来存储ISO-Latin字符集里的字符的话);另一方面,人们在实践中发现即使用2个字节编码也无法表示所有字符,因此出现了UTF-16。UTF-16除了使用2个字节编码外,还使用一对2个字节来表示Unicode里很少用到的字符;另外还有UTF-32,它使用单独的4个字节来编码所有的Unicode字符。

UTF-8的好处:使用不定长字节编码unicode,存储ASCII字符只需一个字节,节省空间流量。(欧美国家肯定喜欢,因为他们很少用到中文之类的字符)

UTF-16的好处:UTF-16比起UTF-8,好处在于大部分字符都以固定长度的字节 (2字节) 储存使用2个字节编码unicode,处理数据速度更快。

比如“中国abc你好”这个字串,如果用不定长的UTF-8编码来存储,那么取‘好’这个字符的时候,要计算“中国abc你”占几个字节,然后再把指针移到‘好’,但是如果用UTF-16来存储,直接就可以算出“好”的位置,因为一个字符占2个字节。如果用UTF-8当数据量很大的时候,定位就更加麻烦.

UTF-32:对每一个Unicode码位使用4个字节。其它的Unicode transformation formats则使用不定长度编码(UTF-16在表示超过2byte的字集时,编码长度不是2个字节)。虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。主要是太浪费空间了。


补充:问题:为什么有了Unicode还要有UTF-8?

<span style="background-color:rgb(255,255,255)"><span style="color:#ff0000;">需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。</span></span><span style="background-color:rgb(255,252,246)">它们造成的直接结果是:出现了unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 unicode 。网络上流行的utf-8就是unicode编码的一类应用.</span>

就如同ASCII一样,ASCII字符都是使用一个字节存储的。因为一个字节就能表示完所有的ASCII字符了。你也可以发明一种新的编码方式,蛋疼的使用2个字节来存储ASCII字符。但肯定不会有人使用你的这种编码。

UTF-8编码就是发明的一种比较好的编码unicode字符的方式,基本上网络上都是使用UTF-8的编码来存储unicode字符。这样比较省空间,传输的时候省流量。但是使用的时候很多时候会转换成UTF-16了来使用,这样好处理数据,不清楚的可以看上面UTF-16的好处。

为了提高Unicode的编码效率,于是就出现了UTF-8编码。UTF-8可以根据不同的符号自动选择编码的长短。比如英文字母可以只用1个字节就够了。
UTF-8的编码是这样得出来的,以”汉”这个字为例:
“汉”字的Unicode编码是U+00006C49,然后把U+00006C49通过UTF-8编码器进行编码,最后输出的UTF-8编码是E6B189。

2,字符编码的作用:

字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、 GB 18030字符集、Unicode字符集等。

计算机要准确的处理各种字符集文字,需要进行字符编码以便计算机能够识别和存储各种文字

如果不编码的话,比如一个数字65,计算机怎么知道它代表个什么?因此我们必须使用字符编码,比如ASCII码,告诉计算机65代表的就是字符‘A’。计算机只能与数字打交道,如果你让它存一个字符‘B’,如果不使用字符编码,它也不知道怎么做。使用字符编码之后,计算机就会存储66来表示‘B’


3,关于乱码:

世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。

使用Windows记事本的“另存为”,可以在ANSI、GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。
比如一个文本文件a.txt内容为hello ,如果使用utf-8编码文件大小就是5个字节;如果使用unicode编码就是10个字节。
如果保存的时候选择为unicode编码,然后传到网上去,网页显示出来可能就是乱码(网页字符用utf-8编码)。
标准的 Unicode 称为UTF-16(UTF:UCS Transformation Format ),所以这里的Unicode编码指的是UTF-16
unicode编码一般指的是标准unicode编码,也就是UTF-16编码。

4,以UTF-16编码还有一个字节序的问题:
UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序
Big Endian(大字节序)和Little Endian(小字节序):
Unicode存储时有个字节序问题,就是一个多字节数字,是从大到小排列还是反之。这和CPU处理有关,一般x86处理时都是倒置的,即大数在前。就像“莫”字的Unicode码0x83ab,按Big Endian就变成了0xab83。
例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到UTF-16字节流“594E”,那么这是“奎”还是“乙”?
BOM(Byte Order Mark):
因为Unicode存储时字节序的问题,在Unicode文本前插入一个不存在的字符(ZERO WIDTH NO-BREAK SPACE)作为标志来分辨两种字节序。
标志0xfeff说明按Big Endian字节序,而0xfffe说明Little-Endian。

UTF-8以单字节为基本单位,所以不存在字节序的问题。
0 0
原创粉丝点击