1. Unicode与ISO 10646

全世界很多个国家都在为自己的文字编码,并且互不想通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”)。因此,同一份文档,拷贝至不同语言的机器,就可能成了乱码,于是人们就想:我们能不能定义一个超大的字符集,它可以容纳全世界所有的文字字符,再对它们统一进行编码,让每一个字符都对应一个不同的编码值,从而就不会再有乱码了。

如果说“各个国家都在为自己文字独立编码”是百家争鸣,那么“建立世界统一的字符编码”则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构试图来做这个事:
(1) 国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。
(2) 统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准(The Unicode Standard,这个前缀Uni很牛逼哦---Unique, Universal, and Uniform)。

1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode 2.0开始,Unicode采用了与ISO 10646-1相同的字库和字码;ISO也承诺,ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值,以使得两者保持一致。两个项目仍都独立存在,并独立地公布各自的标准。不过由于Unicode这一名字比较好记,因而它使用更为广泛。

Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point)。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。

2. UTF-32与UCS-4

在Unicode与ISO 10646合并之前,ISO 10646标准为“通用字符集”(UCS)定义了一种31位的编码形式(即UCS-4),其编码固定占用4个字节,编码空间为0x00000000~0x7FFFFFFF(可以编码20多亿个字符)。

UCS-4有20多亿个编码空间,但实际使用范围并不超过0x10FFFF,并且为了兼容Unicode标准,ISO也承诺将不会为超出0x10FFFF的UCS-4编码赋值。由此UTF-32编码被提出来了,它的编码值与UCS-4相同,只不过其编码空间被限定在了0~0x10FFFF之间。因此也可以说:UTF-32是UCS-4的一个子集

3. UTF-16与UCS-2

除了UCS-4,ISO 10646标准为“通用字符集”(UCS)定义了一种16位的编码形式(即UCS-2),其编码固定占用2个字节,它包含65536个编码空间(可以为全世界最常用的63K字符编码,为了兼容Unicode,0xD800-0xDFFF之间的码位未使用)。例:“汉”的UCS-2编码为6C49。

但俩个字节并不足以正真地“一统江湖”(a fixed-width 2-byte encoding could not encode enough characters to be truly universal),于是UTF-16诞生了,与UCS-2一样,它使用两个字节为全世界最常用的63K字符编码,不同的是,它使用4个字节对不常用的字符进行编码。UTF-16属于变长编码。

前面提到过:Unicode编码点分为17个平面(plane),每个平面包含216(即65536)个码位(code point),而第一个平面称为“基本多语言平面”(Basic Multilingual Plane,简称BMP),其余平面称为“辅助平面”(Supplementary Planes)。其中“基本多语言平面”(0~0xFFFF)中0xD800~0xDFFF之间的码位作为保留,未使用。UCS-2只能编码“基本多语言平面”中的字符,此时UTF-16与UCS-2的编码一样(都直接使用Unicode的码位作为编码值),例:“汉”在Unicode中的码位为6C49,而在UTF-16编码也为6C49。另外,UTF-16还可以利用保留下来的0xD800-0xDFFF区段的码位来对“辅助平面”的字符的码位进行编码,因此UTF-16可以为Unicode中所有的字符编码。

UTF-16中如何对“辅助平面”进行编码呢?

Unicode的码位区间为0~0x10FFFF,除“基本多语言平面”外,还剩0xFFFFF个码位(并且其值都大于或等于0x10000)。对于“辅助平面”内的字符来说,如果用它们在Unicode中码位值减去0x10000,则可以得到一个0~0xFFFFF的区间(该区间中的任意值都可以用一个20-bits的数字表示)。该数字的前10位(bits)加上0xD800,就得到UTF-16四字节编码中的前两个字节;该数字的后10位(bits)加上0xDC00,就得到UTF-16四字节编码中的后两个字节。例如:
(这个字念啥?^_^)
上面这个汉字的Unicode码位值为2AEAB,减去0x10000得到1AEAB(二进制值为0001 1010 1110 1010 1011),前10位加上D800得到D86B,后10位加上DC00得到DEAB。于是该字的UTF-16编码值为D86BDEAB(该值为大端表示,小端为6BD8ABDE)。

4. UTF-8

从前述内容可以看出:无论是UTF-16/32还是UCS-2/4,一个字符都需要多个字节来编码,这对那些英语国家来说多浪费带宽啊!(尤其在网速本来就不快的那个年代。。。)由此,UTF-8产生了。在UTF-8编码中,ASCII码中的字符还是ASCII码的值,只需要一个字节表示,其余的字符需要2字节、3字节或4字节来表示。

UTF-8的编码规则:

(1) 对于ASCII码中的符号,使用单字节编码,其编码值与ASCII值相同(详见:U0000.pdf)。其中ASCII值的范围为0~0x7F,所有编码的二进制值中第一位为0(这个正好可以用来区分单字节编码和多字节编码)。

(2) 其它字符用多个字节来编码(假设用N个字节),多字节编码需满足:第一个字节的前N位都为1,第N+1位为0,后面N-1 个字节的前两位都为10,这N个字节中其余位全部用来存储Unicode中的码位值。

字节数 Unicode UTF-8编码
1 000000-00007F 0xxxxxxx
2 000080-0007FF 110xxxxx 10xxxxxx
3 000800-00FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 010000-10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

5. 总结

(1) 简单地说:Unicode属于字符集,不属于编码,UTF-8、UTF-16等是针对Unicode字符集的编码。

(2) UTF-8、UTF-16、UTF-32、UCS-2、UCS-4对比:

对比 UTF-8 UTF-16 UTF-32 UCS-2 UCS-4
编码空间 0-10FFFF 0-10FFFF 0-10FFFF 0-FFFF 0-7FFFFFFF
最少编码字节数 1 2 4 2 4
最多编码字节数 4 4 4 2 4
是否依赖字节序

VC++宽字符:Unicode和UTF

Unicode和UCS

Unicode和UCS是两个独立的组织分别制定的一套编码标准,但是因为历史的原因,这两套标准是完全一样的。Unicode这个词用得比较多的原因可能是因为比较容易记住,如果没有特别的声明,在本文所提及的Unicode和UCS就是一个意思。Unicode的目标是建立一套可以包含人类所有语言文字符号你想得到想不到的各种东西的编码,其编码容量甚至预留了火星语以及银河系以外语言的空间——开个玩笑,反正简单的说,Unicode编码集足够的大,如果用计算机单位来表示,其数量比3个字节大一些,不到4个字节。

Unicode和UTF

因为Unicode包含的内容太多,其编码在计算机中的表示方法就成为了一个有必要研究的问题。传统编码,比如标准的7位ASCII,在计算机中的表示方法就是占一个字节的后7位,这似乎是不需要解释就符合大家习惯的表示方法。但是当今Unicode的总数达到32位(计算机的最小单位是字节,所以大于3字节,就只能至少用4字节表示),对于大部分常用字符,比如Unicode编码只占一个字节大小的英语字母,占两个字节大小汉字,都用4个字节来储存太奢侈了。另外,如果都用4字节直接表示,就不可避免的出现为0的字节。而我们知道,在C语言中,0x00的字节就是'/0',表示的是一个字符串(char字符串,非wchar_t)的结束,换句话说,C风格的char字符串无法表示Unicode。
因为类似的种种问题,为Unicode在计算机中的编码方法出现了,这就是UTF;所对应的,为UCS编码实现的方式也有自己的说法。一般来说,UTF-x,x表示这套编码一个单位至少占用x位,因为Unicode最长达到32位,所以UTF-x通常是变长的——除了UTF-32;而UCS-y表示一个单位就占用y个字节,所以能表示当今Unicode的UCS-y只有UCS-4,但是因为历史的原因,当Unicode还没那么庞大的时候,2个字节足够表示,所以有UCS-2,现在看来,UCS-2所能表示的Unicode只是当今Unicode的一个子集。
也就是说,如果某种编码,能根据一定的规则算法,得到Unicode编码,那么这种编码方式就可以称之为UTF。

UTF-8和Windows GB2312

UTF-8是一套“聪明”的编码,可能用1,2,3,4个字节表示。通过UTF-8的算法,每一个字节表示的信息都很明确:这是不是某个Unicode编码的第一个字节;如果是第一个字节,这是一个几位Unicode编码。这种“聪明”被称为UTF-8的自我同步,也是UTF-8成为网络传输标准编码的原因。
另外,UTF-8也不会出现0字节,所以可以表示为char字符串,所以可以成为系统的编码。Linux系统默认使用UTF-8编码。
Windows GB2312一般自称为GB2312,其实真正的名字应该是Windows Codepage 936,这也是一种变长的编码:1个字节表示传统的ASCII部分;汉字部分是两个字节的GBK(国标扩(展),拼音声母)。Codepage 936也可以表示为char字符串,是中文Windows系统的默认编码。
我们在第1节中看到的
const char* s = "中文abc";
在Windows中的编码就是Codepage 936;在Linux中的编码就是UTF-8。
需要注意的是,Codepage 936不像UTF,跟Unicode没有换算的关系,所以只能通过“代码页”技术查表对应。

UTF-16和UCS-2

UTF-16用2个字节或者4个字节表示。在2个字节大小的时候,跟UCS-2是一样的。UTF-16不像UTF-8,没有自我同步机制,所以,编码大位在前还是小位在前,就成了见仁见智的问题。我们在第1节中,“中”的UCS-2BE(因为是两个字节,所以也就是UTF-16BE)编码是0x4E2D,这里的BE就是大位在后的意思(也就是小位在前了),对应的,如果是UCS-2LE,编码就成了0x2D4E。
Windows中的wchar_t就是采用UCS-2BE编码。需要指出的是,C++标准中对wchar_t的要求是要能表示所有系统能识别的字符。Windows自称支持Unicode,但是其wchar_t却不能表示所有的Unicode,由此违背了C++标准。

UTF-32和UCS-4

UTF-32在目前阶段等价于UCS-4,都用定长的4个字节表示。UTF-32同样存在BE和LE的问题。Linux的wchar_t编码就是UTF-32BE。在16位以内的时候,UTF-32BE的后两位(前两位是0x00 0x00)等价于UTF-16BE也就等价于UCS-2BE

BOM

为了说明一个文件采用的是什么编码,在文件最开始的部分,可以有BOM,比如0xFE 0xFF表示UTF-16BE,0xFF 0xFE 0x00 0x00表示UTF-32LE。UTF-8原本是不需要BOM的,因为其自我同步的特性,但是为了明确说明这是UTF-8(而不是让文本编辑器去猜),也可以加上UTF-8的BOM:0xEF 0xBB 0xBF

Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4相关推荐

  1. 汉字转16进制java_java实现汉字转unicode与汉字转16进制实例

    本文实例讲述了java实现汉字转unicode与汉字转16进制的实现方法.分享给大家供大家参考.具体实现方法如下: 一.汉字转unicode public static String toUnicod ...

  2. ASP.Net中MD5加密-16位32位

    public string md5(string str,int code) { if(code==16) //16位MD5加密(取32位加密的9~25字符) { return System.Web. ...

  3. java 16进制与汉字_java实现汉字转unicode与汉字转16进制实例

    本文实例讲述了java实现汉字转unicode与汉字转16进制的实现方法.分享给大家供大家参考.具体实现方法如下: 一.汉字转unicode public static string tounicod ...

  4. 16位/32位中断机制比較

    16位/32位中断机制比較 原理: 16位中断机制:使用中断向量表 32位中断机制:使用中段描写叙述符表IDT 位置: 中断向量表的位置是固定的,位于内存的開始0x00000 中断向量符表位置不固定, ...

  5. 外设位宽为8、16、32时,CPU与外设之间地址线的连接方法

    有不少人问到: flash连接CPU时,根据不同的数据宽度,比如16位的NOR FLASH (A0-A19),处理器的地址线要(A1-A20)左移偏1位.为什么要偏1位? 从软件和CPU的角度而言,一 ...

  6. .NET生成常用16、32位MD5加密的两种方法

    //MD5加密函数比较复杂,在.NET中我们不需要编写底层的算法. //平台已经提供两个生成MD5加密的方法: //经过改动一点就可以生成如现在DVBBS等论坛中使用的MD5密码 //⑴:使用C:\W ...

  7. 8位16位32位单片机区别

    8位16位32位区别 8位单片机的数据总线宽度为8位,通常直接只能处理8位数据: 16位单片机的数据总线宽度为16位,通常可直接处理8位或16位数据. 8位数据类型所占大小 16位数据类型所占大小 s ...

  8. 串口控制器,电平脉冲触发,顺序轮换,间歇轮换,电磁阀继电器流水,8路,16路,32路

    串口控制器,电平脉冲触发,顺序轮换,间歇轮换,电磁阀继电器流水,8路,16路,32路 8路串口控制器 电平脉冲触发顺序轮换 间歇轮换 电磁阀继电器流水 8X路串口控制器 电平脉冲触发顺序轮换 间歇轮换 ...

  9. AE-渲染工作站推荐, Wiseteam SP系列16核32线程!

    Wiseteam GE系列通用图形工作站,以至强E5 V3系列CPU为主打的一系列图形工作站双路 12核16核工作站,能满足.图形图像处理.虚拟现实.影视动画等领域. Wiseteam GE180系列 ...

  10. 千元打造双千兆4盘位16核32线程家庭nas服务器,满足你的家庭 all in one方案!

    2023年 高性能框框之王! 小体积4盘位双千兆网卡 就是这么强! 更多NAS or 黑群晖方案 访问DIYNAS:DIYNAS - 家庭服务器构建基地,快速打造你的智能家庭生态圈! 介绍 在科技飞速 ...

最新文章

  1. Protocol Buffer技术详解(语言规范)
  2. javascript对XMLHttpRequest异步请求的面向对象封装
  3. DataList自定义分页
  4. RHEL7.2上基于eSpeak实现TTS
  5. 用USB连接两台电脑
  6. ActiveMQ的安全配置(九)
  7. [机器学习]AutoML --- AutoKeras
  8. 【超级鼠标键盘锁】之远线程注入winlogon.exe进程屏蔽Ctrl+Alt+Del、Win+L
  9. h3c交换机配置文件的导出
  10. 2017沈阳站 Tree
  11. sas sql 读取最后一行数据_SAS基础编程和数据处理
  12. 方德系统装exe文件_国产x86处理器+中科方德定制Linux 完美运行exe
  13. Maven(2)--- 环境配置
  14. java email怎么设置端口号_java mail 设置参数
  15. [转]SDN与OpenFlow技术简介
  16. SCCM2007系列教程之十操作系统部署(三)
  17. 数学建模的13种常用的方法
  18. iOS-Mac下安装CocoaPods
  19. [dpdk] TSC , HPET, Timer, Event Timer,RDTSCP
  20. 华为机考108题(c++)(101-108)

热门文章

  1. python绘制正三角形
  2. qsql 关联_第26篇 数据库(六)SQL关系表格模型QSqlRelationalTableModel
  3. linux4.6 EC11旋转编码器的驱动
  4. ubuntu 16.04中文输入法安装
  5. 2021年机修钳工(中级)考试试卷及机修钳工(中级)模拟考试题
  6. glibc源码分析之utime系列函数
  7. 树莓派从零开始快速入门第9讲——串口
  8. java hibernate 下载,Download the Hibernate Tools
  9. SpringBoot下载Excel模板 无法打开
  10. 自动驾驶传感器---毫米波雷达系统方案