原文地址:http://blog.sina.com.cn/s/blog_6364576a0100gs7q.html

    概念上的澄清:如果有人问你知道不知道unicode呢?你可能会说,我知道,不就是“统一字符编码标准”嘛。对的,你回答的没错,但别人又问你,utf-8是什么呢?你可能会说,utf-8就是unicode。这个回答就不够准确了。Unicode和ASCII、GB2312一样,是一种编码标准。平常更随意的说话是简称为“编码”。这里“编码”的概念,实际上包括了两方面的含义,其一是指该编码所对应的字符集;另一方面是指具体的编码方案,也就是我们通常所说的内码格式。所谓字符集就是指该编码方案包括哪些字符,比如ASCII编码一共包括128个字符,其中有英文大小写字母、数字、标点符号以及一些控制字符。而编码方案是指如何把这128个字符用字节码表示出来,比如说,是把英文字母“A”对应为第1号字符,还是对应为第N号字符呢。在ASCII编码中把字母“A”对应为第65号字符,十六进制表示就是 0x41。

首先来说说最通用的ASCII编码(美国资讯交换标准码)。ASCII编码的128个字符正好可以被一个字节的前七个bit位来表示,而最高的第八个bit位置为0就可以了。几乎现在的所有的编码标准都是和ASCII编码相兼容的。所谓兼容,就是指,新的编码只是扩充ASCII编码,但一个字节的前128个字符都是和ASCII编码完全一致的。我们可以看出,ASCII编码针对英语来讲是足够了的,但它无法表示像中文这样的庞大的字符系统,所以各个国家都针对自己民族语言的特点来扩充ASCII编码。像德语这样的语言,字符元素的数量和英语差不多,所以完全可利用一个字节的剩下的128个字符位置来给自己的语言编码。但对东方语言,事情就没那么简单了,最为庞大的就是汉语了,光简体字形就六、七千个,再加上繁体字、生辟字、古汉字、少数民族的字形以及一些常用的符号、标志啦,总数是在万到十万的量级上。而单字节的最大容量只有256,显然是不能满足汉语的要求的。

双字节的容量有多大呢?256乘以256等于65536,双字节有六万多的空间,这足以满足我们日常的需求了。我们最常用的GB2312、GBK编码标准就都是支持双字节的编码标准,当然,它们也是和ASCII码兼容的。对于每一种编码标准我们都要从字符集和编码方案两个方面去了解。GB2312的字符集,其中除了与ASCII码兼容的那些字符外,再就是包括I级汉字3755字、II级汉字3008字,共计6,763个汉字,另外还有一些符号和标志字符。GB2312的编码方案有两种,一种是用得最为广泛的,就是EUC变字节编码方式。可以用单字节也可以用双字节,为了能区分单字节字符和双字节字符的界限,要求双字节的第一个字节的最高位必须置为1,以就是说,当软件读到一个字节,发现它的值大于128了,就认为它不是一个与ASCII码兼容的字符了,而是一个双字节字符的第一个字节,要连同下一个字节,一起被解读为一个字符。变字节方式的编码方案做到了对单字节编码的扩展,并且可与单字节编码相兼容,但有一个缺点就是在字数统计上变得困难了。另一种编码方案是HZ编码方式,由于现在用的非常少,所以就不介绍了。

GB2312中的汉字全是简体汉字,为了能应用繁体汉字,就有了GB12345标准。GB12345标准的字符集是与GB2312字符集相对应的汉字的繁体字型,当然还有一些增加的字符。它的编码方案与GB2312完全相同,也就是说,同样的一个双字节字符,比如0xB9FA,在GB2312中表示的是“国”字,而在GB12345中表示的就是“國”字。这样表示繁体字有一个弱点,就是无法同时显示简体和繁体字,因为你不能让软件对这个字符用这个编码标准,而对另一个字符用另一编码标准,即使软件支持这样的功能,这一切也太过复杂了。而且随着信息的国际化,越来越多的要求把多种语言集成在一起,比如说一份文档中,不仅含有英文、简体中文和繁体中文,还包括日语和韩语文本。基于这些的考虑,就有了GBK编码标准,GBK标准的字符集共包含20902个汉字、日语中的平假、片假名、日语中的汉字、韩语中的字型以及一些数学符号、标志符号等等。两万多的汉字,基本上覆盖了所有的简体和繁体汉字,以及大部分的生辟字等。GBK的编码方案也是变字节的,并且和GB2312完全兼容,只是在GB2312双字节区域中扩展了编码范围,比如说,GB2312中双字节的第一个字节只能在0xA1~0xFE范围内,而GBK则扩展为在0x81~0xFE范围内。为了与GB2312兼容,在排定了GB2312字符集的位置后,再在扩展的位置上指定剩下的字符。所以原有的GB2312的文档在GBK中都是能正确显示的。

故事到这里应该是已经很完美了,但是还差一些,让我们继续我们的编码探秘之旅。随着计算机在各个领域中的使用,大量的特殊字符涌现出来了,比如说偏微分符号、商标注册符号、五线谱的高音谱号。另一方面就是在学术中要求对古语言字型和各少数民族字型的支持。出于以上这些考虑,就要求有更庞大的编码标准,于是乎双字节的65536个空间也显得不够用了。只能要求更多的字节来容纳这些新的字符。中国恰好是一个历史悠久又多民族的国家,为了能把古汉语的字型以及蒙语、藏语等多民族的语言容纳进来,于是出台了GB18030标准,该字符集光汉字就包括了27533个,还有其它的字符等等。GB18030的编码方案也是变字节的,它支持四个字节的字符。GB18030与GBK是兼容的,GB18030的双字节汉字对应的就是GBK字符集中的所有汉字,其余的6631个汉字是用四字节编码的。

上面的所有只是中国一脉的编码发展,而别的国家的编码方案也是纷繁的,这样的话,在软件的国际化上将变得非常困难。国际标准组织为各国的各种编码标准定义了一个编号,叫做编码页CP(Code Page),比如说,GBK是CP936、GB2312是CP20936、GB18030是CP54936、BIG5是CP950,我们平常用的英文环境是ANSI-Latin I,其编码页是CP1252。不同的编码标准一般情况是不互相兼容的,比如GBK和BIG5。而不同的编码标准的字符集也是不一样的。这在文档的共享和软件的设计上都会产生困难,所以大家需要一种公共的编码方案来整合所有的编码标准,这就是——Unicode。

同样,Unicode规范也分别定义了它的字符集和编码方案。Unicode的字符集很庞大,基本上包括了世界各地的语言和各个领域中的符号,而且随着Unicode标准的更新,更多的字符将被包括进来。单从汉语上来讲,在Unicode2.0时,它支持的中文与GBK中的完全一样,共计20902个汉字;而Unicode3.0,在扩展A区中,又添加了6582个汉字,共计27496个汉字,这与GB18030的容量基本上差不多了。而在Unicode3.1中,还会在扩展B区中添加更多的字符支持。Unicode字符集的定义是抽象的,它只是指定了一个序列,比如说:

U+0020 : SPACE

U+0041 : LATIN CAPITAL LETTER A

U+0042 : LATIN CAPITAL LETTER B

其中的U+0020表示十六进制的第20位的字符是一个叫SPACE的字符,也就是我们通常说的空格符。U+表示这是一个Unicode字符集序列号。这与该字符的实际编码方案是没关系的,完全可以把这个空格符编成任何一个字节形式,而不一定要与0x20相对应。这正是编码方案所要定义的。

Unicode的编码方案有很多种,而且不同种在各自应用的环境有各自便利的地方。我们最常见的utf-8就是Unicode的一种编码方案。如果说一个文件是unicode的,很可能是指utf-16这种编码方案。

我们从Unicode字符集定义的方式,可以相出一种很显然的编码方案,就是直接利用该字符在字符集中的序号来编码,比如那个空格就是编码为0x20,这样很好,但如果有一个序号是U+2020的字符呢?它就无法与这个空格符区分开了。utf-16编码就是完全用双字节来编码的,即使简单的空格符也要被编码成0x0020。这样每个Unicode字符都是两个字节了,很方便字数的统计。当然你可能会说,反正是两个字节,为什么不倒过来编呢,比如说,把空格符编成0x2000,而事实上,一种叫做Unicode Big-Endian(utf-16BE)的编码方案正是这么做的,当然这么做的真实原因是为了方便某种平台对这种编码的读取。于是utf-16也可以称为Unicode Little-Endian(utf-16LE)。为了方便软件能认出文本采用的是哪种编码方案,可以在文本的最前面加上该编码的标志字节,utf-16LE的是0xFF 0xFE,utf-16BE的是0xFE 0xFF。Windows XP下的记事本程序是支持Unicode的,我们可以把一个文件以Unicode方式保存。然后用UEdit以二进制方式打开,就会发现文本的最前面两个字节是编码标志字节。

如果我们的文档保存的大部分信息是英文信息,其中只有很少的中文,那么采用utf-16编码方案就很不经济了,因为每个英文字母都是用两个字节保存的,这样会保存了大量冗余字节0x00。另外一个坏处就是,如果在网络上传输这样的文件,如果由于网络的原因,造成传输中有缺损字节,那么整个utf-16的文档将变成乱码了,因为,你无法知道该文件中的一个字节是Unicode字符的第一个字节还是第二个字节。还有就是utf-16编码方案是与ASCII编码不兼容的。等等这些,都要求我们要有一种更好的编码方案,那就是utf-8。作为Unicode的一种编码方案,它支持的字符集当然是和utf-16是一样的,都是Unicode字符集。utf-8是变字节的编码方案,随着序号的增加,它会从单字节、双字节一直到三字节来表示一个字符,在字符集扩展后,还会出现四字节、五字节的字符。从Unicode字符集序号到utf-8的编码规则如下表显示:

U-00000000 - U-0000007F:

0xxxxxxx

U-00000080 - U-000007FF:

110xxxxx 10xxxxxx

U-00000800 - U-0000FFFF:

1110xxxx 10xxxxxx 10xxxxxx

U-00010000 - U-001FFFFF:

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

U-00200000 - U-03FFFFFF:

111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

U-04000000 - U-7FFFFFFF:

1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

    例如

Unicode字符U+00A9 = 1010 1001(版权符号)在utf-8 里的编码为:

11000010 10101001 = 0xC2 0xA9

而字符 U+2260 = 0010 0010 0110 0000 (不等于符号) 编码为:

11100010 10001001 10100000 = 0xE2 0x89 0xA0

可以看出utf-8是与ASCII码兼容的,所以它会单字节存储ASCII码字符,而汉字将会用三个字节来存储,这样用utf-8来保存全汉字的文件是效率不高的。另外,可看出按照这种编码,第一个字节前面二进制1的个数就是该字符所用的字节数。当丢失了一段字节时,可以很容易判定下一个字符的起使位置。utf-8的编码标志字节是0xEF BB BF。

在一些老式的系统中,比如一些邮件系统,只支持7个bit位字节流,所以也有必要开发一种只支持7位字节的Unicode编码方案,这就是utf-7。它大体的思路是用一个字节0x2B作为一个Unicode字符的开始,然后中间是经过特殊编码的7位的字节序列,当表示完一个字符后,用一个字节0x2d来结束。

Unicode各种编码方案的编码页是:utf-16是CP1200,utf-16BE是CP1201,utf-8CP是65001,utf-7CP是65000。

故事到这里就差不多结束了,最后想说的,编码是字符集和编码方案的一个总称,电脑上的一个文件只是某种编码方案下的二进制字节流的一个存储,在没有任何编码方案标志字节的提示下,我们有理由认为它可能是这种编码方案,也可能是别的某种编码方案,当我们用某种指定的编方案打开时,如果所期望的和实际的编码方案不相同但又不互相兼容时,我们看到的就是乱码了。只有找到了正确的编码方案,就可以正确的解读该文件了。当然有经验的人是可以根据乱码的形式来判断其正确的编码方案的。

Unicode编码的秘密相关推荐

  1. python 2x list 里面的中文打印效果为unicode 编码 的处理方法

    处理方法如下.这个问题在python 3x 中不会出现 #!/usr/bin/python # -*- coding: utf-8 -*- import sys reload(sys) sys.set ...

  2. 【廖雪峰python入门笔记】Unicode编码_UnicodeDecodeError处理

    1.Unicode编码的由来 字符串还有一个编码问题. 计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以, ...

  3. 程序员趣味读物:谈谈Unicode编码

    2019独角兽企业重金招聘Python工程师标准>>> 这是一篇程序员写给程序员的趣味读物.所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级.整 ...

  4. JavaScript为unicode编码转换为中文

    代码laycode - v1.1 关于这样的数据转换为中文问题,常用的以下方法. 1. eval解析或new Function("'+ str +'")() str = eval( ...

  5. js中将 整数转成字符,,将unicode 编码后的字符还原出来的方法。

    一.将整数转成字符: String.fromCharCode(17496>>8,17496&0xFF,19504>>8,19504&0xFF,12848> ...

  6. 将unicode编码的txt文件转为utf-8编码

    利用codes编写: # coding=UTF-8import stringimport codecsdef changecode(): tt=codecs.open('c:\\111.txt','r ...

  7. 关于Laravel中使用response()方法调用json()返回数据unicode编码转换的问题解决

    关于Laravel中使用response()方法调用json()返回数据unicode编码转换的问题解决 参考文章: (1)关于Laravel中使用response()方法调用json()返回数据un ...

  8. pugixml读取unicode编码的xml文件的做法

    作者:朱金灿 来源:http://blog.csdn.net/clever101 实际上在多字节编码的情况下,即以记事本打开显示的ANSI编码的,如下图: pugixml是可以直接读取中文字符的,示例 ...

  9. 常用汉字的unicode 编码

    包含汉字: 的一是了我不人在他有这个上们来到时大地为子中你说生国年着就那和要她出也得里后自以会家可下而过天去能对小多然于心学么之 都好看起发当没成只如事把还用第样道想作种开美总从无情己面最女但现前些所 ...

最新文章

  1. 人工智能:2018年发生了什么变化,2019年又将发生什么变化
  2. 解决oracle绑定变量重复,基于ORACLE SQL优化之绑定变量(4)
  3. java Socket通信(一)
  4. java单词按字典排序_最终Java日志字典:开发人员最常记录的单词是什么?
  5. python的concat用法_python的concat等多种用法详解
  6. python的平方运算符_python入门之与用户交互、运算符
  7. ubuntu默认面板被删除后的恢复办法
  8. 如果粒子运动只受力影响,那么意识从何而来
  9. 来成都旅游,千万不要做的22件事!
  10. 谷歌浏览器 发送到剪切板_将Google搜索结果发送到您的新闻阅读器
  11. python组合的语法_在Python中使用语法sugar-to-function组合是个好主意吗?
  12. 【给初学者,大佬见笑】100%成功UEFI安装双硬盘单系统Ubuntu最合理分区安装指南+ubuntu20.04安装
  13. 第十一周OJ-Q50解题方法
  14. windows平台mosquitto的安装与使用
  15. 985计算机英语六级,大学英语六级比四级难多少?985学长含泪告诉你!
  16. 完美解决Windows10安装HCL模拟器各种疑难问题!!!
  17. VBScript终极破产版石头剪刀布游戏(VBS语言实现)
  18. 中国软件外包IT公司最新排名
  19. 从键盘输入三角形的直角边,利用hypot()函数输出三角形的斜边
  20. 理解CGI、FCGI、php-cgi、php-fpm的概念

热门文章

  1. HTTP协议【报文格式】
  2. App Store Connect 上传app时,屏幕快照尺寸5.8-Inch,6.5-Inch,iPhone XS,iPhone XS Max, iPhone XR
  3. js 遍历 JSON数据
  4. 使用java正则表达式的正确姿势
  5. [老老实实学WCF] 第三篇 在IIS中寄存服务
  6. 明日之后手游安卓版今日10点上线!来啊,一起来撸狗啊
  7. 数据结构课本课后题算法
  8. 【个人项目】电商价格监控——项目介绍和架构演变
  9. 一文详解XMind的安装教程
  10. c语言数码管显示乘法口诀,数码管随机模拟显示乘法口诀实验报告