码迷,mamicode.com
首页 > 其他好文 > 详细

聊聊计算机中的编码(Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等)

时间:2016-04-29 22:10:53      阅读:458      评论:0      收藏:0      [点我收藏+]

标签:

作为一个程序员,一个中国的程序员,想来“乱码”问题基本上都遇到过,也为之头疼过。出现乱码问题的根本原因是编码与解码使用了不同而且不兼容的“标准”,在国内一般出现在中文的编解码过程中。

我们平时常见的编码有Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等,弄清这些编码之间的关系,就不难理解“乱码”出现的原因以及解决办法。

所谓字符集编码其实就是将字符(包括英文字符、特殊符号,控制字符,数字,汉子等)与计算机中的一个数字(二进制存储)一一对应起来,用这个数字来表示该字符,存储该字符的时候就存储这个数字。比如a对应数字97。因此,理解编码很简单,所有的编码都是字符与数字的一种对应关系

ASCII编码:

计算机最早出现在美国,因此老美搞编码只需要对26个英文字符大小写以及常用的字符对应数字就可以了,这种对应就是ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)码。标准ASCII 码使用7 位二进制数来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。这样可以表示27=128个字符。标准ASCII码的最高位恒为0,没有使用。

iso8859-1:

随着计算机的推广,世界各地都开始使用计算机。各国不同语言对字符编码提出了新的需求,原ASCII的128个字符已经显得严重不足。那怎么办呢,ASCII码不是只用了一个字节中的7位吗,还剩余1位呢?那就赶紧用上吧!于是人们把编码扩展到了8位,即256个字符的编码,这就是ISO8859-1。这种扩展保持了与ASCII的兼容性,即最高位为0的ISO8859-1编码等同于ASCII码。

GBK码:

等到计算机进入中国,人们又头疼了。常用汉字就有6000多个,像ASCII那样用一个字节来编码撑爆了也不够啊。但是这难不倒智慧的中国人们,我们直接定下标准:小于127的字符与原意义相同(保持与ASCII的兼容性),但是两个大于127的字符连在一起时,就表示一个汉字。这样我们就凑出来了7000多个简体汉字的编码了。此外,这些编码还对ASCII码中已有的标点、数字、字母都用两字节重新编码,这就是通常说的“全角”字符。这种编码就是GB2312

但是中国的汉字实在太多了,GB2312还是不够用,一些不常用的汉字还是显示不出来啊。于是我们不得不继续挖掘GB2312的潜能,干脆只要求第一个字节大于127而不管后一个字节的大小了。这种扩展之后的编码方案称为GBK

Unicode码:

中国造出了GBK编码,其他国家呢,他们也要显示自己的文字啊。于是各个国家都搞出了一套自己的编码标准,结果相互之间谁也不懂谁的编码,互不兼容。这样不行啊,于是乎ISO(国际标谁化组织)不得不站出来说话了:“你们都不要各自搞编码了,我给你们搞一套统一的!”。于是ISO搞了一个全球统一的字符集编码方案,叫UCS(Universal Character Set),俗称Unicode

Unicode标准最早是1991年发布了,目前实际应用的版本是UCS-2,即使用两个字节编码字符。这样理论上一共可以编码216=65536个字符,基本能够满足各种语言的需求。

UTF8、UTF16码:

其实Unicode码已经完美解决编码国际化问题了,那utf8和utf16又是神马东东,用来解决什么问题呢?

前面已经说过,编码只是字符与数字的一种对应关系,这完全是一个数学问题,跟计算机和存储以及网络都没有半毛钱关系。Unicode码就是这样一种对应关系,它并没有涉及到如何存储以及传输的问题。看下面一个例子:

假如某个字符的Unicode编码为0xabcd,也就是两个字节。那存储的时候是哪个字节在前哪个在后呢?网络传输的时候又是先传输哪个字节呢?计算机从文件中读取到0xabcd又是怎么知道这是两个ASCII码还是一个Unicode码呢?

因此需要一种统一的存储和传输格式来标示Unicode码。这种统一的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。编码utf8和utf16就是因此而产生的。

其中utf16与16位的Unicode码完全对应。在Mac和普通PC上,对于字节顺序的理解是不一致的。比如MAC是从低字节开始读取的,因此前文的0xabcd如果按照所见的顺序存储,则会被MAC认为是0xcdab,而windows会从高字节开始读取,得到的是0xabcd,这样根据Unicode码表对应出来的字符就不一致了。

因此,utf16使用了大端序(Big-Endian,简写为UTF-16 BE)、小端序(Little-Endian,简写为UTF-16 LE)以及BOM(byte order mark)的概念。如果在windows上用记事本写上一些中文字符并以Unicode码格式保存,然后使用十六进制查看器打开即可以看到文件的前两个字节为0xfffe(0xfffe在Unicode码中不对应字符),用来标记使用小端序存储(windows平台默认使用小端序),下图为中文“你好”二字在windows7上的十六进制数据。

技术分享技术分享

由于Unicode统一采用16位二进制编码字符,试想一篇英文文章如果用UTF16来存储的话整整比用ASCII存储多占用一倍的存储空间(英文字符的Unicode码高字节是0),这样白白的浪费让人于心不忍啊。于是utf8诞生了。utf8是一种变长编码,根据不同的Unicode码值采用不同的存储长度。那么问题又来了,既然是变长的系统怎么知道几个字节表示一个字符编码呢?对于这类问题计算机中通用的处理方式就是使用标志位,就像ip段的划分一样。具体如下:

0xxxxxxx,如果是这样的01串,也就是以0开头后面是啥就不用管了XX代表任意bit.就表示把一个字节做为一个单元.就跟ASCII完全一样.

110xxxxx 10xxxxxx.如果是这样的格式,则把两个字节当一个单元

1110xxxx 10xxxxxx 10xxxxxx 如果是这种格式则是三个字节当一个单元.

由于utf8可能不止一个字节,因此存储时同样需要标记从哪端读取之类的,因此类似utf16编码,utf8同样有大端序、小端序和BOM的概念。

Unicode码的发展

Unicode码采用16位编码世界字符其实还是有点捉襟见肘的。因此从 Unicode 3.1 版本开始,设立了16个辅助平面(相当于Unicode码又扩充了4位),使 Unicode 的可使用空间由六万多字增至约一百万字。用白话说就是增加了几个区段,比如原始版本的Unicode码的范围是0x0000 ~ 0xffff,第一辅助平面的范围是0x10000~0x1FFFD,第二辅助平面的范围是0x20000 ~ 0x2FFFD,……

最新版的Unicode码规范提出了UCS-4,即使用4字节做Unicode编码。类似前面的utf16,对于UCS-4的Unicode码,可以采用utf32来存储,同样需要定义大小端序和BOM信息。

聊聊计算机中的编码(Unicode,GBK,ASCII,utf8,utf16,ISO8859-1等)

标签:

原文地址:http://www.cnblogs.com/firser/p/5447590.html

(1)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!