字符编码

来源:互联网 发布:环球科学 知乎 编辑:程序博客网 时间:2024/05/17 01:25

字符编码知识总结


 

目录

 


 

基础知识

字符:各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

编码:将汉字、字符变为计算机所熟悉的二进制的规则。

解码:将二进制转换为汉字或字符的规则、过程。

字符集:一个系统所支持的所有抽象字符的集合。

字符编码:是一套规则,可以将符号转换为计算机可以接受的数字系统的数。

常见字符集及编码

ASCII字符

ASCII字符集:即美国信息交换标准代码,是基于拉丁字母的单字节编码系统。主要包括控制字符(回车、退格、换行),可显示字符(英文大小写字符、阿拉伯数字和西文字符)。

ASCII编码:将ASCII字符集转换为计算机可接受的数字系统的数的规则。使用七位表示一个字符,共128个字符。为表示欧洲常用字符,对ASCII进行了扩展。ASCII扩展集使用8位表示一个字符,共256个字符。

ASCII编码的优缺点:只能显示二十六个基本拉丁字母,阿拉伯数字,和英式标点符号。

映射规则:如下图


GB2312(GB0)

GB2312字符:包括6763个简体汉字,还包括数学符号、罗马希腊的字母、日文的假名。而且将ASCII中原本包含的数字、标点、字母重新编为两个字节长的编码,即所说的“全角”字符。而原来127号以下的称为“半角”字符。

GB2312编码:将127号之后的字符去掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时就表示一个汉字,前面的字节(高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE。

GB2312的特点:所收录的汉字已经包含了99.75%的汉字,但是对于人名(如中国总理朱镕基的“镕”),古汉语、台湾香港使用的繁体字、日语朝鲜语等方面出现的罕用字不能处理,从而导致GBK的出现。

映射规则:如下图

GBK

GBK字符:GBK向下完全兼容GB2312-80编码。 支持GB2312-80编码不支持的部分中文姓,中文繁体,日文假名,还包括希腊字母以及俄语字母等字母。

GBK编码:字符有一字节和双字节编码,007F范围内是一位,和ASCII保持一致,此范围内严格上说有96个文字和32个控制符号。

之后的双字节中,前一字节是双字节的第一位。总体上说第一字节的范围是81FE(也就是不含80FF),第二字节的一部分领域在407E,其他领域在80FE

GBK 亦采用双字节表示,总体编码范围为 8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。如图:


GBK的特点:这种编码不支持韩国字,也是其在实际使用中与unicode编码相比欠缺的部分。

GBK映射规则:


GB18030

GB18030字符:在GBK基础上增加了CJK统一汉字扩充A、扩充B的汉字。与GBK基本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。

GB18030编码:单字节,其值从0到0x7F。

双字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x40到0xFE(不包括0x7F)。

四字节,第一个字节的值从0x81到0xFE,第二个字节的值从0x30到0x39,第三个字节从0x81到0xFE,第四个字节从0x30到0x39。


BIG5

BIG5字符:是通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。

BIG编码:Big5码是一套双字节字符集,使用了双八码储存方法,以两个字节来安放一个字。第一个字节称为“高位字节”,第二个字节称为“低位字节”。“高位字节”使用了0x81-0xFE,“低位字节”使用了0x40-0x7E,及0xA1-0xFE。

Unicode

Unicode出现的原因:像天朝一样,当计算机传到世界各个国家时,为了适合当地语言和字符,设计和实现类似GB232/GBK/GB18030/BIG5的编码方案。这样各搞一套,在本地使用没有问题,一旦出现在网络中,由于不兼容,互相访问就出现了乱码现象。为了解决这个问题,一个伟大的创想产生了——Unicode。Unicode编码系统为表达任意语言的任意字符而设计。它使用4 字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表唯一的至少在某种语言中使用的符号。可以这样理解:Unicode是字符集,UTF-32/ UTF-16/ UTF-8是三种字符编码方案。

Unicode字符就已经包含了超过十万个字符(在2005年,Unicode 的第十万个字符被采纳且认可成为标准之一)、一组可用以作为视觉参考的代码图表、一套编码方法与一组标准字符编码、 一套包含了上标字、下标字等字符特性的枚举等。

Unicode 编码:

Utf-32: 上述使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph),每个数字代表唯一的至少在某种语言中使用的符号的编码方案,称为UTF-32。UTF-32又称UCS-4是一种将Unicode字符编码的协定,对每个字符都使用4字节。就空间而言,是非常没有效率的。

Utf-16:尽管Unicode字符非常多,但是实际上大多数人不会用到超过前65535个以外的字符。因此,就有了另外一种Unicode编码方式,叫做 UTF-16(因为16位 = 2字节)。UTF-16将0–65535范围内的字符编码成2个字节,如果真的需要表达那些很少使用的"星芒层(astral plane)"内超过这65535范围的Unicode字符,则需要使用一些诡异的技巧来实现。UTF-16编码最明显的优点是它在空间效率上比UTF- 32高两倍,因为每个字符只需要2个字节来存储(除去65535范围以外的),而不是UTF-32中的4个字节。

如果字符编码U小于0x10000,也就是十进制的0到65535之内,则直接使用两字节表示;

如果字符编码U大于0x10000,由于UNICODE编码范围最大为0x10FFFF,从0x10000到0x10FFFF之间 共有0xFFFFF个编码,也就是需要20个bit就可以标示这些编码。用U'表示从0-0xFFFFF之间的值,将其前 10 bit作为高位和16 bit的数值0xD800进行 逻辑or 操作,将后10 bit作为低位和0xDC00做 逻辑or 操作,这样组成的 4个byte就构成了U的编码。

多字节的Unicode编码方式定义了一个"字节顺序标记(Byte Order Mark)",它是一个特殊的非打印字符,你可以把它包含在文档的开头来指示你所使用的字节顺序。对于UTF-16,字节顺序标记是U+FEFF。如果收 到一个以字节FF FE开头的UTF-16编码的文档,你就能确定它的字节顺序是单向的(one way)的了;如果它以FE FF开头,则可以确定字节顺序反向了。

Utf-8: Format)是一种针对Unicode的可变长度字符编码(定长码,也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。

优点

1.        UTF-8是ASCII的一个超集。因为一个纯ASCII字符串也是一个合法的UTF-8字符串,所以现存的ASCII文本不需要转换。为传统的扩展ASCII字符集设计的软件通常可以不经修改或很少修改就能与UTF-8一起使用。

2.        使用标准的面向字节的排序例程对UTF-8排序将产生与基于Unicode代码点排序相同的结果。(尽管这只有有限的有用性,因为在任何特定语言或文化下都不太可能有仍可接受的文字排列顺序。)

3.        UTF-8和UTF-16都是可扩展标记语言文档的标准编码。所其它编码都必须通过显式或文本声明来指定。

4.        任何面向字节的字符串搜索算法都可以用于UTF-8的数据(只要输入仅由完整的UTF-8字符组成)。但是,对于包含字符记数的正则表达式或其它结构必须小心。

5.        UTF-8字符串可以由一个简单的算法可靠地识别出来。就是,一个字符串在任何其它编码中表现为合法的UTF-8的可能性很低,并随字符串长度 增长而减小。举例说,字符值C0,C1,F5至FF从来没有出现。为了更好的可靠性,可以使用正则表达式来统计非法过长和替代值(可以查看W3 FAQ: Multilingual Forms上的验证UTF-8字符串的正则表达式)。

缺点

因为每个字符使用不同数量的字节编码,所以寻找串中第N个字符是一个O(N)复杂度的操作 — 即,串越长,则需要更多的时间来定位特定的字符。同时,还需要位变换来把字符编码成字节,把字节解码成字符。

UTF-8编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F |0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

编码杂谈

大小端问题

以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

因此,第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

Unicode与UTF-8之间的转换

在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。


里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。

1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

ANSI编码:

不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。这些使用 2 个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文系统下,ANSI 编码代表 GB2312 编码,在日文操作系统下,ANSI 编码代表JIS 编码。 不同 ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段 ANSI 编码的文本中。 当然对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表1个字符。这一点是ASNI编码与Unicode编码之间最大也最明显的区别。

为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。  对于ANSI编码而言,0x00~0x7F之间的字符,依旧是1个字节代表1个字符。这一点是ANSI编码与Unicode(UTF-16)编码之间最大也最明显的区别。比如“A君是第131号”,在ANSI编码中,占用12个字节,而在Unicode(UTF-16)编码中,占用16个字节。因为A和1、3、1这4个字符,在ANSI编码中只各占1个字节,而在Unicode(UTF-16)编码中,是需要各占2个字节的。


 

参考资料:

1,   http://wenku.baidu.com/view/a8bd7380e53a580216fcfea7.html

2,   http://blog.csdn.net/chaijunkun/article/details/4654397

3,   http://wenku.baidu.com/link?url=_5os_LGwcd7uI1sSu49kn_ubVBMAfSjREEPDdygH6--6Wx0iMYP2T6X689Elng2xuUEEOVX3mG4BG17Ga9Fq3ZxW0WBHkQb9VZNmDe9_PK_

4,   http://baike.baidu.com/link?url=rzZN2uwn0wA_ivpeqxks3y6DyFBtAB13IC2aeK3lNpfsev2Yk542m-lbQhFE4cg1qKlgVZi3mQyMGwy57okUrK

 


0 0