计算机网络诞生后,大家慢慢地发现一个问题:一个字节放不下一个字符了!因为需要交流,本地化的文字需要能够被支持。

  最初的字符集使用7bit来存储字符,因为那时只需要存下一些英文字母和符号。后来虽然扩展到使用8bit来存储一个字符了(这种方式被国际标准化组织收录,成为ISO8859-1。在字符集发展历程中国际标准化组织一直发挥着重要作用。),也还是无法存储诸如中文的字符。

  混乱的年代到来了。为了存储下自己的文字,各个国家和地区(多为非拉丁语系的民族,因为这些语种字符数很庞大)各自使用两个字节即16bit来存放一个字符。他们把首字节的前2^7个位留给一个字节能存下的字符(如英文字母和标点符号),而后的位和后面的字节一起组成适用于本地文字的字符。这中方式一直沿用至今,如GB2312、GBK(此编码为微软为简体中文用户设计的)、GB18030、BIG5等。使用这种方式有一个问题:不同的数值(假如我们把字符换算成数字)在不同的字符集可能有不同的意义,甚至使用不同字体也会呈现出不同的效果!而且从一个字符集到另一个字符集的转化也会非常麻烦!

  标准化一直在进行。为了解决上述麻烦,各种机构都做出了不同的努力。以微软为代表的操作系统可能更多的是提供用户可选择的语言和区域设置,并使用如CodePage(代码页,Windows操作系统对不同地区不同字符集的支持方式。如GBK为CP936)来隔离差异,国际标准化组织(ISO)编纂了ISO10646来规范和整合字符集(被成为通用字符集 Universal Character Set,UCS )。统一码联盟(由各个大型企业及组织共同维护)发布了统一码(Unicode)项目。

  起初,UCS和Unicode各自为政,但1991年前后他们都发现:世界不需要两个不一样的“统一”、“通用”的字符集。所以他们联合起来维护一个字符集,现在他们的差别大概是发布新版本时使用什么字体了-_-。

  UCS和Unicode都使用最大32bit来存储字符,他们(其实是一样的,不过还是区分一下)的码位(字符数)有1114112个,从0x0到0x0x10FFFF。

  大家可能会奇怪,32bit最多可以表示超42亿个字符(即从0x0到0xFFFFFFFF),为什么只使用了其中这么小一部分呢?其实,这里面还有一些其他原因。

  使用32bit来存储字符看起来是一件一劳永逸的方式,但如果这32bit是定宽的(即任何字符都要使用完这32bit)的话就不可避免的造成空间的浪费,程序效率也会降低!

  能不能把UCS(Unicode)设计成“变宽”的呢?聪明的设计师想到了一个主意,他们发明了一种名为“统一码转换格式”即UTF的来将字符对应的数字(可能从小于127至大于100万不等)转化为多个字节来进行存储。

  简单说来,UCS或Unicode只是定义了从0到1114112这些数字各自是什么字符(而指示界面上该怎么显示这个字符则是由“字体”来管理,比如Windows下“微软雅黑”字体就是这个样子的(部分):

  

)。而如果从1~4个字节(变宽)还原出这个数字(或字符)就是UTF的事儿了。

  比如“汉”字,对应数字为23383,那么要使用3字节的UTF8格式字节进行存储(原因我们下面再讲),或者1字节的UTF16或1字节的UTF32。

  “汉” UTF8 = {0xE6, 0xB1, 0x89}

    UTF16 = {0x6c49}

    UTF32 = {0x6c49}(高位补0可省略)

  Unicode字符集的划分大概有两种:按“单元(Cell)”划分(Unicode官方文档是这样分的)和按“平面(Plane)”划分。一个单元为128个字符,一个平面有65536个字符。

  我们通常使用的一个平面取值为0x0到0xFFFF,这个平面被成为BMP(Basic Multilingual Plane)即“平面0”。由于这个平面只是用两个字节就可以完整表示,字符集又可以成为UCS-2(即使用2字符的“通用字符集”,UCS-4即为4字节,将UCS-4的高两位去除即为UCS-2)。

  我们常用的27973个汉字都存放与平面0上,整个Unicode共定义了71226个汉字(Unicode5.0.0),平面2的43253个字符都是汉字。

  

  UTF之间的关系和转换。上文说道,“汉”字需要3个UTF8字节来存储,这是因为要符合UTF格式的规范。

  一个模版可以告诉我们UTF8是怎样存储数据的:

Unicode编码(16进制) 
UTF-8 字节流(二进制)
000000 - 00007F
0xxxxxxx
000080 - 0007FF
110xxxxx 10xxxxxx
000800 - 00FFFF
1110xxxx 10xxxxxx 10xxxxxx
010000 - 10FFFF
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

  可以看到,如果使用两个字节来存储数据,UTF8最多可以存储2^11个字符,最大的数字为0x7FF即2047,显然无法存下数字为23383的“汉”字。

  而通过模版我们也可以看出Unicode的最大bit数为21。

  数字向UTF的转换也很简单了,把数字换成二进制(不足21位的高位补0),然后填入对应UTF的模版(UTF16和UTF32的模版大家请自行查看,LE和BE区别在于高位和低位的位置,Windows和Linux为LE,MacOS为BE)中替换xxxxxxx就行了!很简单吧。

  UTF在文件中的存储。UTF格式在文件中总有固定文件头:

UTF编码
Byte Order Mark
UTF-8
EF BB BF
UTF-16LE
FF FE
UTF-16BE
FE FF
UTF-32LE
FF FE 00 00
UTF-32BE
00 00 FE FF

  如“汉”字在文件中的存储(不包括头):

Unicode编码
UTF-16LE 
UTF-16BE 
UTF32-LE 
UTF32-BE
0x006C49
49 6C
6C 49
49 6C 00 00
00 00 6C 49

  

  各个系统和语言对Unicode的支持:

    Windows NT从底层支持Unicode(不幸的是,Windows 98只是小部分支援Unicode)。先天即被ANSI束缚的C程序设计语言通过对宽字元集的支持来支持Unicode。

    Windows底层使用UTF16,Linux使用UTF32(未考证)。

    C#和Java支持UTF16且是默认行为(如字符串天生为UTF16格式字符数组,Java还可以使用'\uxxxx'格式声明一个字符)。

    XML及其子集HTML对UTF16支持很好,为跨平台你可以使用'&#xxxx;'来声明一个字符。

欢迎您移步我们的交流群,无聊的时候大家一起打发时间:

或者通过QQ与我联系:

(最后编辑时间2013-09-17 20:59:38)

字符集和编码——Unicode(UTF&UCS)深度历险的更多相关文章

  1. 各个系统和语言对Unicode的支持 字符集和编码——Unicode(UTF&UCS)深度历险

    http://www.cnblogs.com/Johness/p/3322445.html 各个系统和语言对Unicode的支持: Windows NT从底层支持Unicode(不幸的是,Window ...

  2. Unicode(UTF&UCS)深度历险

    Unicode(UTF&UCS)深度历险 计算机网络诞生后,大家慢慢地发现一个问题:一个字节放不下一个字符了!因为需要交流,本地化的文字需要能够被支持. 最初的字符集使用7bit来存储字符,因 ...

  3. WEB开发中的字符集和编码

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  4. Ruby:字符集和编码学习总结

    背景 Ruby直到1.9版本才很好的支持了多字节编码,本文简单总结了今天学习的关于Ruby编码方面的知识. 字符串可以使用不同的编码 在.NET中字符串的编码是一致的,Ruby允许字符串有不同的编码, ...

  5. .NET:字符集和编码学习总结

    背景 一直没有深入的学习字符集和编码的知识(现在也没有深入),今天查阅了一些资料,弄明白了一些事情,本文就简单记录一下. 字符集和编码 字符集是指一些符号组成的集合,编码是对指定字符集如何表示为字节的 ...

  6. java中的字符集和编码

    前言 上次对计算机中的“字符集”和“编码”分别进行了总结,并指出二者之间的区别,不要搞混了,不清楚的再回到上一章看一下.今天再总结下java中是如何使用字符集(主要是Unicode字符集,其他常用字符 ...

  7. Linux字符集和编码

    计算机内部,所有信息最终都是一个二进制值形式存放 字符集 字符集:charset是character set的简写,即二进制和字符的对应关系,不关注最终的存储形式 编码 字符集编码:encoding是 ...

  8. Unicode字符集和编码方式

    通常将一个标准中能够表示的所有字符的集合称为字符集,比如ISO/Unicode所定义的字符集为Unicode.在Unicode中,每个字符占据一个码位/Unicode 编号(用4位十六进制数表示,Co ...

  9. C#和VC++字符集和编码

    C# char 关键字用于声明 .NET framework 使用 Unicode 字符表示 System.Char 结构的实例. Char 对象的值是 16 位数字 (序号值.)将字符表示为 UTF ...

随机推荐

  1. SQL SERVER 2005 数据库置疑修复

    alter database 置疑数据库 set emergency go alter database 置疑数据库 set single_user with rollback immediate g ...

  2. 当echarts的legend字数过多的时候变成省略号

    legend: { data: ['国有土地使用','食品药品安全','生态环境和资源保护','国有财产保护'], orient: 'horizontal', left: '10', bottom:' ...

  3. 阿里巴巴MySQL DBA面试题答案[转]

    无意中看到阿里巴巴的面试题,,借此回首DBMS时刻趁热打铁巩固一下基础 拿到题目大概浏览了一遍难度大概在中上游水平,自己跪了接近35%的题目 自己答题如下,欢迎大家讨论分析题 1 2 3 4 5 6 ...

  4. Java常用测试工具

    第一部分:九款性能测试 Java入门 如果你才刚开始接触Java世界,那么要做的第一件事情是,安装JDK——Java Development Kit(Java开发工具包),它自带有Java Runti ...

  5. CentOS SVN服务器管理多项目

    一 需求 一般来说,公司有多个项目,在搭建好SVN服务器之后,就需要使用SVN来实现不在一个项目中的开发人员不能访问其它项目中的代码. 假设: 有3个项目:project1.project2.proj ...

  6. loadrunner上传文件到网盘

    有人提问,loadrunner 上传文件搞不好,请求帮忙处理.让提供网址,用fiddler抓包上传部分,主要有3个请求 第一个请求GET https://yun.xxx.com/api/files/u ...

  7. 第三部分:Android 应用程序接口指南---第三节:应用程序资源---第一章 资源提供

    第1章 资源提供 你应该经常外部化你应用程序代码中的资源,比如图片.字符串等,这样有利于你独立处理这些资源.你也应该根据特定的设备配置提供一些可替代的资源,并且把他们分组保存在指定的路径名下.运行时, ...

  8. Python--Redis实战:第四章:数据安全与性能保障:第7节:非事务型流水线

    之前章节首次介绍multi和exec的时候讨论过它们的”事务“性质:被multi和exec包裹的命令在执行时不会被其他客户端打扰.而使用事务的其中一个好处就是底层的客户端会通过使用流水线来提高事务执行 ...

  9. python 数据结构之顺序列表的实现

    算法简要: 追加直接往列表后面添加元素,插入是将插入位置后的元素全部往后面移动一个位置,然后再将这个元素放到指定的位置,将长度加1删除是将该位置后面的元素往前移动, 覆盖该元素,然后再将长度减1 #! ...

  10. mercurial的几个易用性小技巧

    其实这两年,能够采用mercurial的项目我都尽量用,甚至有些上游是git的,或者需要托管到公司内gitlab上与别人协作的,我都装上hg-git.无它,只是因为mercurial易用性比git好得 ...