字符集和编码——Unicode(UTF&UCS)深度历险
计算机网络诞生后,大家慢慢地发现一个问题:一个字节放不下一个字符了!因为需要交流,本地化的文字需要能够被支持。
最初的字符集使用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)深度历险的更多相关文章
- 各个系统和语言对Unicode的支持 字符集和编码——Unicode(UTF&UCS)深度历险
http://www.cnblogs.com/Johness/p/3322445.html 各个系统和语言对Unicode的支持: Windows NT从底层支持Unicode(不幸的是,Window ...
- Unicode(UTF&UCS)深度历险
Unicode(UTF&UCS)深度历险 计算机网络诞生后,大家慢慢地发现一个问题:一个字节放不下一个字符了!因为需要交流,本地化的文字需要能够被支持. 最初的字符集使用7bit来存储字符,因 ...
- WEB开发中的字符集和编码
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- Ruby:字符集和编码学习总结
背景 Ruby直到1.9版本才很好的支持了多字节编码,本文简单总结了今天学习的关于Ruby编码方面的知识. 字符串可以使用不同的编码 在.NET中字符串的编码是一致的,Ruby允许字符串有不同的编码, ...
- .NET:字符集和编码学习总结
背景 一直没有深入的学习字符集和编码的知识(现在也没有深入),今天查阅了一些资料,弄明白了一些事情,本文就简单记录一下. 字符集和编码 字符集是指一些符号组成的集合,编码是对指定字符集如何表示为字节的 ...
- java中的字符集和编码
前言 上次对计算机中的“字符集”和“编码”分别进行了总结,并指出二者之间的区别,不要搞混了,不清楚的再回到上一章看一下.今天再总结下java中是如何使用字符集(主要是Unicode字符集,其他常用字符 ...
- Linux字符集和编码
计算机内部,所有信息最终都是一个二进制值形式存放 字符集 字符集:charset是character set的简写,即二进制和字符的对应关系,不关注最终的存储形式 编码 字符集编码:encoding是 ...
- Unicode字符集和编码方式
通常将一个标准中能够表示的所有字符的集合称为字符集,比如ISO/Unicode所定义的字符集为Unicode.在Unicode中,每个字符占据一个码位/Unicode 编号(用4位十六进制数表示,Co ...
- C#和VC++字符集和编码
C# char 关键字用于声明 .NET framework 使用 Unicode 字符表示 System.Char 结构的实例. Char 对象的值是 16 位数字 (序号值.)将字符表示为 UTF ...
随机推荐
- IntelliJ IDEA全局内容搜索和替换
在做项目时,有时会在整个项目里或指定文件夹下进行全局搜索和替换,这是一个很方便功能.使用方法如下: 一.全局搜索 1.使用快捷键Ctrl+Shift+F打开搜索窗口,或者通过点击Edit–> ...
- Machine、Swarm、Compose、SocketPlane这些Docker生态圈软件各解决了哪些问题?
Machine:解决的是操作系统异构安装Docker困难的问题,没有Machine的时候,CentOS是一种,Ubuntu又是一种,AWS又是一种.有了Machine,所有的系统都是一样的安装方式. ...
- js事件探秘
Javascript中的事件,可以和html交互. 事件流 IE&Opera:事件冒泡 其他浏览器: 事件捕获 事件冒泡:事件由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传 ...
- cmd adb批量安装与卸载
批量安装: SET dir=%~dp0echo dir is: %dir%cd /d %dir%for /R %dir% %%i in (*.apk) do adb install %%i 批量卸载: ...
- linux/unix命令参考
- 简单shell指令
第一部分 简单的常用指令 1.date命令 date 2.显示日历 cal 3.显示当前目录 pwd 4.切换当前工作目录 默认情况下,超级用户的主目录是/root,而普通用户的主目录是/home下 ...
- 收藏清单: python测试数据生成及代码扫描最全工具列表
Test Data manipulation 测试数据的操作和处理 faker - 生成假数据的python库 fake2db - 创建假数据库 ForgeryPy - 使用起来很简单的假数据生成库. ...
- appium 获取android 粘贴板上的内容
appium 新版本增加了获取粘贴板的内容.如果使用appium旧版本,获取粘贴板的内容不是那么容易的,甚至百度谷歌各种搜,都无法找到合适的解决方法.新版本获取android 粘贴板内容就显得很容易了 ...
- VSCode配置TypeScript
网上教程一堆,记录下我认为的关键点: 1.创建tsconfig.json,使用命令行在项目文件夹下输入“tsc --init”即可: 2.创建tasks.json,在VSCode中,使用ctrl+sh ...
- Ubuntu 卸载重装 IntelliJ Idea Community
参考: https://stackoverflow.com/questions/22983101/how-to-uninstall-intellij-idea-on-ubuntu-13-10 @SLH ...