字符编码(ucs2-+unicode-+utf8-+gb2312) 所属栏目:编码知识 18年03月05日 标签:

 

字符编码

 

版本

修订日期

修订内容

修订人

V0.1

2008-12-1

初始化


V1.0

2008-12-11

第一版


V1.1

2008-12-13

First   reported


V1.2

2008-12-14

添加ASCII码表


V1.3

2008-12-18

添加code page


V1.4

2008-12-23

添加BOM


 

1       ASCII

American Standard Code for Information Interchange,美国标准信息交换码。因为计算机只能表示和存储二进制的数据,所以需要对常用的52个字母,阿拉伯数字等字符进行编码,为了便于信息交换,需要一个统一的标准,于是American National Standard Institute(ANSI)制定了这个ASCII码,并于1967年成为美国国家标准,后被ISO(International Standardization Organization)国际标准化组织定为国际标准ISO646

ASCII属于单字节编码,即使用一个字节(8 bytes)进行编码,因此最多只能表示256个字符。基础的ASCII使用7bits编码,最高位位为0,或者用于奇偶校验。ASCII编码适用于所有的拉丁字母。

0x00 – 0x1F:为控制字符

ASCII编码可以满足美国的拉丁字母需求,但是不能满足其他语种的需求,例如中日韩的象形文字,所以导致下面编码的出现。

具体定义如下:

 

 

 

十六进制

字符

意义

十六进制

字符

意义

0x00

NULL

空字符

0x10



0x01

SOH

Start of head

0x11



0x02

STX

Start of text

0x12



0x03

ETX

End of text

0x13



0x04

EOT

End of Transmission

0x14



0x05

ENQ

Enquiry

0x15



0x06

ACK

Acknowledge

0x16



0x07

BELL

铃声

0x17



0x08

BS

Backspace

0x18



0x09

TAB

Horizontal tab

0x19



0x0A

LF

Line Feed

0x1A



0x0B

VT

Vertical tab

0x1B



0x0C



0x1C



0x0D

CR

Carriage return

0x1D



0x0E

SO

Shift out

0x1E



0x0F

SI

Shift in

0x1F



 

 

 

 

2       UCS

国际标准ISO 10646定义了通用字符集 (Universal Character Set, UCS)。 UCS是所有其他字符集标准的一个超集。它保证与其他字符集是双向兼容的,就是说,如果你将任何文本字符串翻译到UCS格式,然后再翻译回原编码,你不会丢失任何信息。

UCS 包含了用于表达所有已知语言的字符,不仅包括拉丁语,希腊语,斯拉夫语,希伯来语,阿拉伯语,亚美尼亚语和乔治亚语的描述,还包括中文,日文和韩文这样的象形文字,以及平假名,片假名,孟加拉语,旁遮普语,果鲁穆奇字符(Gurmukhi),泰米尔语,印.埃纳德语(Kannada),Malayalam,泰国语,老挝语,汉语拼音(Bopomofo),Hangul,Devangari,Gujarati,Oriya, Telugu 以及其他数也数不清的语。对于还没有加入的语言, 由于正在研究怎样在计算机中最好地编码它们, 因而最终它们都将被加入。这些语言包括Tibetian, 高棉语, Runic(古代北欧文字), 埃塞俄比亚语, 其他象形文字, 以及各种各样的印-欧语系的语言, 还包括挑选出来的艺术语言比如Tengwar, Cirth 和克林贡语(Klingon). UCS 还包括大量的图形的, 印刷用的, 数学用的和科学用的符号, 包括所有由 TeX, Postscript, MS-DOS,MS-Windows, Macintosh, OCR 字体, 以及许多其他字处理和出版系统提供的字符。

ISO 10646定义了一个 31 位的字符集。然而, 在这巨大的编码空间中, 迄今为止,只分配了前 65534 个码位 (0x0000 到 0xFFFD)。这个 UCS 的 16位子集称为基本多语言面 (Basic Multilingual Plane, BMP)。将被编码在 16 位 BMP 以外的字符都属于非常特殊的字符(比如象形文字), 且只有专家在历史和科学领域里才会用到它们。按当前的计划, 将来也许再也不会有字符被分配到从 0x000000 到 0x10FFFF 这个覆盖了超过 100 万个潜在的未来字符的 21 位的编码空间以外去了。ISO 10646-1 标准第一次发表于 1993 年, 定义了字符集与 BMP 中内容的架构。定义 BMP 以外的字符编码的第二部分 ISO 10646-2 正在准备中, 但也许要过好几年才能完成。新的字符仍源源不断地加入到 BMP 中, 但已经存在的字符是稳定的且不会再改变了。

UCS 不仅给每个字符分配一个代码,而且赋予了一个正式的名字,表示一个 UCS 或 Unicode 值的十六进制数, 通常在前面加上 "U+", 就象 U+0041 代表字符"拉丁大写字母A". UCS 字符 U+0000 到 U+007F 与 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 与 ISO 8859-1(Latin-1) 也是一致的. 从 U+E000 到 U+F8FF, 已经 BMP 以外的大范围的编码是为私用保留的。

UCS只是规定如何编码,并没有规定如何传输、保存这个编码。例如“汉”字的UCS编码是6C49,我可以用4个ASCII数字来传输、保存这个编码;也可以用UTF-8编码:3个连续的字节E6 B1 89来表示它。关键在于通信双方都要认可。UTF-8、UTF-7、UTF-16都是被广泛接受的方案。UTF-8的一个特别的好处是它与ISO- 8859-1完全兼容。UTF是“UCS Transformation Format”的缩写。

 


 

3       UTF8

UTF8并不算是一种电脑编码,而是一种储存和传送的格式,如前所述,每个Unicode/UCS字符都以 2或4个bytes来储存,看看以下的比较:

以"I am Chinese"为例

用ANSI储存:             12 Bytes

用Unicode/UCS2储存:     24 Bytes + 2 Bytes(header)

用UCS4储存:             48 Bytes + 4 Bytes(header)

以"我是中国人"为例

用ANSI储存:         10 Bytes(GB2312)

用Unicode/UCS2储存: 10 Bytes + 2 Bytes(header)

用UCS4储存:         20 Bytes + 4 Bytes(header)

 

由此可见直接以Unicode/UCS的原始形式来储存是一种极大的浪费,而且也不利于互联网的传输(中文稍为合算一点^_^)。

有见及此,Unicode/UCS的压缩形式--UTF8出 现了,套用官方网站的首句话『UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters.』,由于UTF也适用于编码UCS,故亦可称为『UCS transformation formats (UTF)』

UTF8是以8bits即1Bytes为编码的最基本单位,当然也可以有基于16bits和32bits的形式,分别称为UTF16和UTF32,但目前用得不多,而UTF8则被广泛应用在文件储存和网络传输中。

 

编码原理

先看这个模板:

UCS-4 range (hex.)     UTF-8 octet sequence (binary)

0000 0000-0000 007F -- 0xxxxxxx

0000 0080-0000 07FF -- 110xxxxx 10xxxxxx

0000 0800-0000 FFFF -- 1110xxxx 10xxxxxx 10xxxxxx

0001 0000-001F FFFF -- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

0020 0000-03FF FFFF -- 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

0400 0000-7FFF FFFF -- 1111110x 10xxxxxx ... 10xxxxxx

 

编码步骤:

1) 首先确定需要多少个8bits(octets)

2) 按照上述模板填充每个octets的高位bits

3) 把字符的bits填充至x中,字符顺序:低位→高位,UTF8顺序:最后一个octet的最末位x→第一个octet最高位x

不知大家看懂了没有,其实不懂也无所谓,反正又不用自己算,程式可以完全代劳。以UTF8格式储存的文件档首标识为EF BB BF。

效率

  从上述编码原理中得出的结论是:

1.每个英文字母、数字所占的空间为1 Byte;

2.泛欧语系、斯拉夫语字母占2 Bytes;

3.汉字占3 Bytes。

由此可见UTF8对英文来说是个非常诱人的方案,但对中文来说则不太合算,无论用ANSI还是 Unicode/UCS2来编码都只用2 Bytes,但用UTF8则需要3 Bytes。

以下是一些统计资料,显示用UTF8来储存文件每个字符所需的平均字节: 1.拉丁语系平均用1.1 Bytes;

2.希腊文、俄文、阿拉伯文和希伯莱文平均用1.7 Bytes;

3.其他大部份文字如中文、日文、韩文、Hindi(北印度语)用约3 Bytes;  4.用超过4 Bytes的都是些非常少用的文字符号。


 

4       中文编码

4.1            GB2312

GB2312码是中华人民共和国国家汉字信息交换用编码,全称《信息交换用汉字编码字符集——基本集》,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。

在国标GD2312 —80中规定,所有的国标汉字及符号分配在一个94行、94列的方阵中,方阵的每一行称为一个“区”,编号为01区到94区,每一列称为一个“位”,编号 为01位到94位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号(使用Big Edian编码,高字节在前)。用区位码就可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的区位码。例如:汉字“母”字的区位码是3624,表明它在方阵的36区24位,问号“?”的区位码为0331,则它在03区3l位。在这94*94的区位中,其中:

01-09区为符号、数字区

10-15区空白区

16-87区为汉字区

88-94区空白区

在汉字区分为两级:第 一级是常用汉字计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺 序排列。故而GB2312最多能表示6763个汉字

汉字的区码和位码取值都在01~94之间,如果直接使用区位码作为机器内码的话,就会与ASCII码混淆。为了避免这个冲突,需要避开基本ASCII码中的控制码 (00H~1FH),还需与基本ASCII码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上20H,在此基础上再加80H(此处“H”表示 前两位数字为十六进制数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字节,这两位字节的机内码按如下规则表示:

高位字节 = 区码 + 20H + 80H(或区码 + A0H)

低位字节 = 位码 + 20H + 80H(或位码 + AOH)

由于汉字的区码与位码的取值范围的十六进制数均为01H~5EH(即十进制的01~94),所以汉字的高位字节与低位字节的取值范围则为A1H~FEH(即十进制的161~254)。

例如,汉字“啊”的区位码为1601,区码和位码分别用十六进制表示即为1001H,它的机内码的高位字节为B0H,低位字节为A1H,机内码就是B0A1H。

 

 

4.2            GBK

GB2312只收录了6763个汉字,因此许多以前很少使用的生僻字没有收录,现在这些字也许变得流行了,例如:朱镕 基的“镕”字,未收入GB2312-80,现在大陆的报业出刊只得使用(金+容)、(金容)、(左金右容)等来表示,形式不一而同,这使得表示、存储、输 入、处理都非常不方便。

GBK:汉字国标扩展码,基本上采用了原来GB2312-80所有的汉字及码位,并涵盖了原Unicode中所有的汉字20902,总共收录了883个符号, 21003个汉字及提供了1894个造字码位。 Microsoft简体版中文Windows 95就是以GBK为内码,又由于GBK同时也涵盖了Unicode所有CJK汉字,所以也可以和Unicode做一一对应

P- Windows3.2和苹果OS就是以GB2312为基本汉字编码, Windows 95/98则以GBK为基本汉字编码、但兼容支持GB2312。

GBK编码是中国大陆制订的、等同于UCS的新的中文编码扩展国家标准。GBK工作小组于1995年10月,同年12月完成GBK规范。该编码标准兼容GB2312,共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库。

总体编码范围为8140-FEFE之间,首字节在81-FE之间,尾字节在40-FE之间,剔除XX7F一条线。

GBK共收入21886个汉字和图形符号,包括:

* GB2312中的全部汉字、非汉字符号。

* BIG5中的全部汉字。

* 与ISO 10646相应的国家标准GB13000中的其它CJK汉字,以上合计20902个汉字。

* 其它汉字、部首、符号,共计984个。

 

GBK编码区分三部分:

1.   汉字区 包括

GBK/2:OXBOA1-F7FE, 收录GB2312汉字6763个,按原序排列;

GBK/3:OX8140-AOFE,收录CJK汉字6080个;

GBK/4:OXAA40-FEAO,收录CJK汉字和增补的汉字8160个。

2.   图形符号区 包括

GBK/1:OXA1A1-A9FE,除GB2312的符号外,还增补了其它符号

GBK/5:OXA840-A9AO,扩除非汉字区。

3.   用户自定义区

即GBK区域中的空白区,用户可以自己定义字符。

 

GBK码对字库中偏移量的计算公式为:

[(GBKH-0xB0)*0x5E+(GBKL-0xA1)]*(汉字离散后每个汉字点阵所占用的字节)

 

4.3            GB18030

GB18030 是最新的汉字编码字符集国家标准, 向下兼容 GBK GB2312 标准。 GB18030 编码是一二四字节变长编码。一字节部分从 0x0~0x7F ASCII 编码兼容。 二字节部分, 首字节从 0x81~0xFE, 尾字节从 0x40~0x7E 以及 0x80~0xFE, GBK 准基本兼容。 四字节部分, 第一字节从 0x81~0xFE, 第二字节从 0x30~0x39, 第三和第四字节的范围和前两个字节分别相同。 四字节部分覆盖了从 0x0080 开始, 除去二字节部分已经覆盖的所有 Unicode 3.1 码位。也就是说, GB18030 编码在码位空间上做到了与 Unicode 标准一一对应,这一点与 UTF-8 编码类似。

 

4.4            Big 5

BIG5是通行于台湾、香港地区的一个繁体字编码方案。虽然存在一些瑕疵,但广泛应用于电脑行业,尤其是互联网中,从而成为一种事实上的行业标准。

1983年10月,台湾国家科学委员会、教育部国语推行委员会、中央标准局、行政院共同制定了《通用汉字标准交换码》,后经修订于1992年5月公布,更名为《中文标准交换码》,BIG5是台湾资讯工业策进会根据以上标准制定的编码方案。

BIG5码是双字节编码方案,其中第一个字节的值在OxAO-OxFE之间,第二个字节在Ox40-Ox7E和OxA1-OxFE之间。

BIG5收录13461个汉字和符号,包括:

* 符号408个,编码位置A140-A3BE

* 常用字5401个,编码位置A440-C67E,包括台湾教育部颁布的《常用国字标准字体表》的全部汉字4808个,台湾教科书常用字587个,异体字6个。

* 次常用字7652个,编码位置C940-F9D5,包括台湾教育部颁布的《次常用国字标准字体表》的全部汉字6341个,《罕用国字标准字体表》中使用频率较高的字1311个。

 

5       细节

1.   在双字节编码中,GB内码的存储格式始终是big endian,即高位在前。

2.   GB2312的 两个字节的最高位都是1。但符合这个条件的码位只有128 * 128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响 DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。

3.   从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容

6       BOM

所谓的BOM是指字节序标志(Byte Order Mark),是为了区分big还是little字节序的,在UCS 编码中有一个叫做"ZERO WIDTH NO-BREAK SPACE"的字符,它的编码是FFFE。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符"ZERO WIDTH NO-BREAK SPACE"。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符"ZERO WIDTH NO-BREAK SPACE"又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符"ZERO WIDTH NO-BREAK SPACE"的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。