南京音乐推荐联合社

unicode、utf-8、ansi、gbk、gb2312编码详解

阿信在努力 2019-06-27 07:58:07

unicode、utf-8、ansi、gbk、gb2312编码详解

前言

作为一个开发人员或是测试人员,免不了要与各种各样的编码打交道,而且这些各种编码总是让人头大,现在我们就来揭开他们的庐山真面目

移动还是联通?

在开始本文前,我需要大家思考一个问题:你知道联通为什么干不过移动吗?
我们来看看微软站在哪边吧,用记事本写下联通两个字:

这里写图片描述


保存后再从新打开刚刚的文件,你会发现微软表态了:

这里写图片描述


微软的意思大概就是,联通是啥玩意儿?同样的方法,移动就没毛病。想知道为什么吗?那就要仔细往下看了


ascii

很久以前,计算机制造商有自己的表示字符的方式。他们并不需要担心如何和其它计算机交流,并提出了各自的 方式来将字形渲染到屏幕上。随着计算机越来越流行,厂商之间的竞争更加激烈,在不同的计算机体系间转换数 据变得十分痛苦,人们厌烦了这种自定义造成的混乱,于是就有人站出来阻止这种混乱,他振臂高呼,组织各大厂商开始统一编码,与秦始皇统一文字与异曲同工之妙,他们用一个字节来表示他们使用的字符,a,b,c,d什么的,实际上他们只用了128个,其中0~31是控制字符,32~127是可显示字符,这就是后来的ascii编码了:

这里写图片描述


但是啊,这些老美万万没想到,计算机是如此的受人欢迎,很快计算机就在
其它国家流行开了,其它国家看有很多本土常用的字符,ascii中没有,于是就有人想啊,一个字节中不是才用了一半吗,这不最高位还没用吗,于是各个国家就开始用最高位来扩展这个ascii以便能够表示自己国家的一些字符,但是这并不是对每个国家都有效的,特别是我们的大天朝,你英文就那几个,但是我们文化博大精深啊,我们的汉字那可就有好几万个,你就给我一个字节,我怎么玩?


gb2312、big-5与gbk

一个字节要表示我国那么多中文,是万万办不到的,那么就只好再加一个字节了:
我们不客气地把那些127号之后的奇异符号们直接取消掉, 规 定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前 面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样 我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、 日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的 编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 "GB2312"。GB2312 是对 ASCII 的中文扩 展。 但是,你以为这样就够用了吗?当然不行,gb2312能够表示很多简体汉字,但是繁体怎么办呢?台湾群众很不满啊,于是也自己搞了一套编码,于是big-5诞生了,你以为这样就完了?gb2312仅仅可以表示6000多个常用汉字你让其它不常用的怎么办?于是扩展呗,把之前gb2312中没有利用的位好好利用起来,就成了gbk,这又增加了20000多个汉字,但是咱们少数名族也要用电脑啊,于是有了后来的 GB18030

GB2312和GBK都是用两个字节来编码的,就算用完所有的位(256*256=65536)也不够为所有的汉字 编码。于是就有了目前最新的GB18030,它采用类似UTF-8的编码方式进行编码(每个字符的编码可以是 1、2或4个字节),拥有上百万个编码空间,足以支持中日韩三国所有汉字,并且还可以支持国内少数民族 的文字。

但是这毕竟是属于一种“方言”式的编码,很多其它国家是不懂你这个编码的,于是各种编码的出现又导致了混乱,于是unicode闪亮登场了!

unicode与utf-8

在这之前我们需要先理清个概念:
Unicode只是简单的字符到数字的一个映射,就相当于一个电话本,它是没有字节限制的,是可以无限表示的,它也不管一个字符在计算机中式怎么存储的,具体怎么存储涉及到字符编码,而unicode应该叫做字符集
Unicode为世界上的每一个字符都弄了一个对应的数字,所以就不会再存在乱码问题了,比如,汉字 严 的 Unicode 是十六进制数 4E25 ,转换成二进制数足足有15位( 100111000100101 ),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号, 可能需要3个字节或者4个字节,甚至更多,这里会出现几个问题:

A.我们怎么知道是三个字节一起表示一个字符,还是说三个字节分别表示三个字符
B.之前一个ascii字符只需要一个字节,但是现在用了unicode普遍使用三个或四个字节,那使用英文就回浪费很多字节
于是针对unicode出现了很多不通的编码方案,这些方案就是为了解决unicode再计算机中具体怎么存储的问题,经常听说的有:utf-8、utf-16、utf-32
utf-16是用两个或四个字节表示一个字符
utf-32使用四个字节表示一个字符

而utf-8是可变长的编码方案,它可以用1~4个字节表示不同字符,显而易见,前面两种编码方案会浪费很多字节,而utf-8就很好了,所以我们现在也通常使用utf-8。
那utf-8具体是怎么编码unicode的呢?
1)对于单字节的符号,字节的第一位设为 0 ,后面7位为这个符号的 Unicode 码。因此对于 英语字母,UTF-8 编码和 ASCII 码是相同的。
2)对于 n 字节的符号( n > 1 ),第一个字节的前 n 位都设为 1 ,第 n + 1 位设为 0 ,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

根据utf-8的编码规则,我们就可以发现它很好的解决了前面的两个问题:
兼容ascii且不适用多余的字节,多字节的字符,我们可以通过判断它的第一个字符来确定字节数。
这是一份编码表,其中xxx处填写相应的unicode值

这里写图片描述


举个例子:
“侠”的unicode表示是4fa0,根据上表我们来计算一下它的utf-8编码:
根据上表,4fa0在第三行的位置,也就是我们需要把unicode值依次填入1110xxxx 10xxxxxx 10xxxxxx中,开始填字游戏吧:
11100100 10111110 10100000
转换为16进制后:E4BEA0


ansi又是什么?

其实ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。你 的美国同事Bob的系统中ANSI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而你 的系统中(“汉字”正常显示)ANSI编码其实是GBK编码,而韩文系统中(“한국어”正常显示)ANSI编码其 实是EUC-KR编码。
windows系统通过Windows code pages的值来确定当前系统的编码方式。

现在我们就可以来看一下联通干不过移动的原因了,因为我们在记事本中不指定存储编码时默认时ansi,在中国的电脑上也就是gbk编码,而联通的gbk编码是:
c1 1100 0001 
aa 1010 1010 
cd 1100 1101 
a8 1010 1000 
有没有发现它和utf-8有点像?没错,它就是与utf-8编码冲突了,在我们第二次打开记事本的时候,记事本误以为它是utf-8编码。于是就按照utf-8的格式解析了,我们去掉模板后,再补上前导0:00000000 01101010
转为16进制:006A
对应unicode是小写字符j

这里写图片描述


但是后一个字节用同样的方法后是:0368不能表示任何字符,所以记事本机会乱码了。


参考资料

ansi是什么编码:http://www.cnblogs.com/malecrab/p/5300486.html

阮一峰的解释:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

中文字符的几种编码:http://www.cnblogs.com/malecrab/p/5300497.html

细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 :
http://www.cnblogs.com/malecrab/p/5300503.html

国外比较好的一篇文章(推荐):https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/


阿信在努力

一起见证未来

关注

Copyright © 南京音乐推荐联合社@2017