编码问题

以前对编码问题一直比较头疼,于是今天google了一翻,把一些心得和学到的点点东西贴上来。

问题提出:
1、刚开始接触编码的时候就是ASCII,那个时候知道了一个八位的二进制对应一个字母或者符号数字等等,然后以为世界上所有的字符都是这样子的。
2、后面一想不对呀, 中文有那么多汉子,在加上西方很多国家都有许多不同的文字, 光是东亚中日韩的文字就足够多了。 那就想2个字节,3个字节,4个字节应该就可以解决了,以为在来个这样的编码就可以了。
3、可是为什么还有那么多utf8,utf16 gbk,unicode什么乱七八糟的东西呢?
 
4、我做过两个比较大型的项目,里面统统都用utf8编码。这些编码到底什么关系呢? 
 
今天上网想把这些东东弄个明白,于是google了一通。
这两篇是很不错的文章:a、 http://blog.csdn.net/stilling2006/article/details/4129700 
 
1)、ASCII 应该算是纯英文世界里简单而且便捷的编码了,如果只有他们在用计算机,那就不至于出现现在那么多编码问题了。
这段话我觉得描述的很精确:(来自百度百科)
ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。标准ASCII码也叫基础ASCII码,使用7位二进制数来表示所有的大写和小写字母,数字0到9、标点符号,以及在美式英语中使用的特殊控制字符(这里需要特别注意:ASCII码与标准ASCII码的位数上的区分,标准ASCII码是7位二进制表示)。
其他的也就算是非ASCII码了,b文章里面有讲。世界上其他国家也有很多的文字,在使用8位就不够用了。 gbk这东西就是我们的前辈们想把中文也在计算机里面传承然后发明出来的,但必须安装特定的软件才能使用这些中文。后面又因为需要显示更多的文字GBK 扩成了GB18030。这些a文章里都有讲到。  
全世界都这样自己去弄自己的编码肯定不行的,于是ISO出来搞出来一个unicode了。
 
2)、unicode编码
        Unicode也叫统一码,万国码,顾名思义世界上所有的国家都可以使用的编码。计算机刚开始发展的时候内存容量是很小的,随着硬件的不断更新,内存容量已经足够满足字符编码的需要了。 
Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。
通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。UCS-2用两个字节编码,UCS-4用4个字节编码。
 
当然Unicode和另外一个联盟 ISO和各大厂商的联盟之间也存在着竞争,但他们意识到这根本没有这个必要,于是他们在后面也达成了协议统一编码。
 
其实可以这样理解 Unicode就是解决一个编码对应一个字符的问题,我只要拿到这样一个编码我就可以从Unicode表中找到对应的字符(当然也可能是符号或者是其他东东)。 Unicode也算是一种字符集。 关于字符集,代码页,字符编码表可以参考wiki (http://zh.wikipedia.org/wiki/%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81 ) 
 
2)UTF-8 
 UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码定长码),也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。 
 
这里要解决的问题就是 Unicode统一规定用三个四个字节来表示字符,对于一些前面两个字节都是0x00的字符来说是太浪费了,于是就选择了一种前缀码来表示Unicode了。因为UFT-8比较常用所以啰嗦一下:

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

已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

  关于UTF-16 UTF32可以参考下wiki的内容。

 

3)大端小端

不同的计算机会以不同的字节序来保存字节。比如说字符:字符U+4E2D, 可能保存的是 4E2D或者2D4E,这取决于你的计算机是大端还是小端。

对于这个字节序的概念可以采用《UNIX网络编程》卷1:套接字联网API 中文板63页原文76页的图3-9来说明。 

我们假设有这样一段内存  : AABB ;  AA属于高序字节, BB属于低序字节。 

如果是小端字节序:内存地址增大方向是从 BB--》AA的,BB属于地址a的话,AA就属于地址a+1

大端字节序: 内存地址增大方向是从AA->BB的,AA属于地址a的话,BB就属于地址a+1

上面所提到的4E2D, 在大端字节序的机器里是 4E2D,而在小端字节序的机器里是2D4E。

网络字节序的概念也是同理。

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

 

 

参考文章:http://blog.csdn.net/ce123/article/details/6971544

wiki 以及前面提到的a b c 文章

 

posted @ 2013-03-31 00:59  seanoop  阅读(154)  评论(0)    收藏  举报