1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 字符集 字符编码编码总结:ANSI UNICODE MBCS ASCII等等

字符集 字符编码编码总结:ANSI UNICODE MBCS ASCII等等

时间:2021-09-06 12:54:03

相关推荐

字符集 字符编码编码总结:ANSI UNICODE MBCS ASCII等等

目录

一、字符集与字符编码

二、字符集的发展

1. 单字节字符集(SBCS)

2. 多字节字符集(MBCS)

3. 宽字节字符集(Unicode)

三、UTF - Unicode/UCS Transformation Format

1. UTF-8

2. UTF-16

3.UTF-32

四、代码页(Code Page)

五、Unicode编程

一、字符集与字符编码

字符集(英文名:Character set)是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。

计算机要准确的处理各种字符集文字,就需要进行字符编码(英文名:Character encoding),以便计算机能够识别和存储各种文字。字符编码也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的编码方式有:ASCII、GB2312、BIG5、Unicode(UCS-2,UCS-4)、UTF-8和BASE64等等。

简单说:

字符集:为每一个「字符」分配一个唯一的ID(学名为码位/码点/ Code Point)字符编码:将「码位」转换为字节序列的规则(编码/解码可以理解为加密/解密的过程)

例如:Unicode是「字符集」,UTF-8是「字符编码」。

在Unicode出现以前,字符集与字符编码是没有区分的。例如ASCII、GB2312、GBK、BIG5等等标准即是字符集,也是字符编码。

二、字符集的发展

计算机字符集可归类为三种,单字节字符集(SBCS)、多字节字符集(MBCS)和宽字符集(Unicode字符集)。

1. 单字节字符集(SBCS)

单字节字符集,称之为SBCS,它的所有字符都只有一个字节的长度。常见字符集有:ASCII码和扩展ASCII码。SBCS字符串由一个零字节结尾,数据类型是char。

ASCII:目前计算机中用得最广泛的单字节字符集及其编码,是由美国国家标准局(ANSI)制定的ASCII(AmericanStandardCode forInformationInterchange,美国标准信息交换码),它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。ASCII码适用于所有拉丁文字,它用7位二进制数进行编码(其最高位(bit7)被用做奇偶校验位),可以表示128个字符。

第0~32号及第127号(共34个)是控制字符或通信专用字符,如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BEL(振铃)等。

第33~126号(共94个)是字符,其中第48~57号为0~9 10个阿拉伯数字;65~90号为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。

参考:ASCII码-基本的ASCII码和扩展的ASCII码,最全的ASCII码对照表

2. 多字节字符集(MBCS)

当非拉丁语国家人民使用计算机时,需要将他们自己使用的文字(字符)进行编码。此时ASCII码占用1个字节预留的空间(128~255)就不够用了。因此,非拉丁语国家对自己的文字进行编码时,通常采用在ASCII基础上扩展,并用多个字节表示一个字符。这种字符集就叫多字节字符集。同SBCS一样,MBCS字符串也由一个零字节结尾,数据类型也是char。

例如聪明的中国人民为了解决汉子编码时想到了这样的办法。我们不客气地把那些127号之后的奇异符号们直接取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都重新编了两个字节长的编码,这就是常说的“全角”字符,而原来在127号以下的那些就叫“半角”字符了。中国人民看到这样很不错,于是就把这种汉字方案叫做“GB2312”。GB2312是对ASCII的中文扩展。但是中国的汉字太多了,我们很快就发现有许多人的人名没有办法在这里打出来,特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把GB2312没有用到的码位找出来老实不客气地用上。后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为GBK标准,GBK包括了GB2312的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了GB18030

类似的,其他的国家和地区也在ASCII码基础上扩展出自己的字符集。例如:BIG5(台湾)、JIS(日本)。这些扩展得来的多字节字符集彼此并不兼容,会将大于127的码点(Code Point)定义成自己的字符。因此,采用MBCS设计的程序、网页在不同地区解码时就可能出现乱码!

3. 宽字节字符集(Unicode)

由于MBCS是各个国家和地区为本地文字进行编码的标准方案,彼此互不相通,不同的语言字符编码值相同却代表不同的符号(例如:韩文编码EUC-KR中“한국어”的编码值正好是汉字编码GBK中的“茄惫绢”)。因此,同一份文档,拷贝至不同语言的机器,就可能成了乱码。为了解决这一问题,人们设想定义一个超大字符集,能容纳全世界所有已知字符、文字,并进行统一编码,于是设计了通用字符集。

如果说“各个国家都在为自己文字独立编码”是百家争鸣,那么“建立世界统一的字符编码”则是一统江湖,谁都想来做这个武林盟主。早前就有两个机构试图来做这个事:

国际标准化组织(ISO),他们于1984年创建ISO/IEC JTC1/SC2/WG2工作组,试图制定一份“通用字符集”(Universal Character Set,简称UCS),并最终制定了ISO 10646标准。统一码联盟,他们由Xerox、Apple等软件制造商于1988年组成,并且开发了Unicode标准(The Unicode Standard)。

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

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

其中第0号平面又叫基本多文种平面。基本多文种平面,BMP(Basic Multilingual Plane),或称第零平面(Plane 0),是Unicode中的一个编码区段。编码从U+0000至U+FFFF。Unicode基本多文种平面的示意图如下。每个写着数字的格子代表256个码点。(CJK是中日韩文字区域,这个区域很大哦!)

三、UTF - Unicode/UCS Transformation Format

早期字符集与字符编码是不区分的,例如ASCII编码、GB2312编码、GBK编码等等。这些标准直接取字符的码点(Code Point)进行16进制编码即可以完成编码。

当Unicode出现时,由于其定义了多个平面,而最常用的又是基本多文本平面。因此,最开始的编码方式是UCS-2,即读基本多文种平面的65536个字符进行2个字节的16进制编码。这种编码的缺点是:

不兼容ASCII码。所有ASCII字符都需要加上0x00的字节,极大地浪费了存储空间。因此,后续发展了UTF-8编码。不支持辅助平面字符码点(surrogate code points)。后续发展了UTF-8、UTF-16、UCS-4、UTF-32等等。

其中UTF-16对基本多文种平面的编码与UCS-2是相同的,因此UTF-16可以视为UCS-2的父集。UTF-32原本是UCS-4的子集,但JTC1/SC2/WG2声明,所有未来对字符的指定都将会限制在BMP及其14个补充平面。于是就现状而言,除了UTF-32标准包含额外的Unicode意涵,UCS-4和UTF-32大体是相同的。

UTF是UnicodeTransformationFormat的缩写,即Unicode字符集转换格式。目前最常用的是UTF-8和UTF-16。其中UTF-8在网页、移动端使用最多。

1. UTF-8

UTF-8采用变长字节对字符进行1-4个字节的编码,具体取决于码点数值中有效位的数量。

UTF-8编码中,前128个字符(US-ASCII)需要一个字节。接下来的1,920个字符需要两个字节进行编码,其中涵盖了几乎所有拉丁字母字母的其余部分,还包括希腊语,西里尔语,科普特语,亚美尼亚语,希伯来语,阿拉伯语,叙利亚语,塔那那语和N'Ko字母以及组合变音词马克。剩余基本多语言平面中的字符需要三个字节,其中几乎包含所有常用字符,包括大多数字符中文,日文和韩文字符。Unicode的其他平面中的字符需要四个字节,其中包括不常见的CJK字符,各种历史脚本,数学符号和表情符号(象形符号)。其最大的优势是与标准ASCII码完全兼容,对ASCII字符编码只采用1个字节编码。在网页端传输因为有大量英文字符,采用UTF-8编码能极大地减少存储空间。但是UTF-8对汉字并不“友好”,大部分汉字都需要占用3个字节存储。这也是为什么大部分中文网页或者程序依然会采用GB2312、GBK编码的原因。

以下为UTF-8对Unicode中文字符编码的一个示例:

这就是将U+5B87按照UTF-8编码为字节序列E5AE87的过程。

2. UTF-16

UTF-16对基本多文种平面字符进行两个字节编码,并且依赖字节序(Byte Order Mark,简称BOM)。对于非基本文种平面的辅助平面字符,采用四个字节编码。

UTF-16对基本多文种平面的字符进行编码时,编码值直接取字符的Unicode码点值。这样绝大多数语言的字符都能利用两个字节进行编码。除基本多文种平面外,还剩0xFFFFF个码位(并且其值都大于或等于0x10000)。对于“辅助平面”内的字符来说,如果用它们在Unicode中码点值减去0x10000,则可以得到一个0~0xFFFFF的区间(该区间中的任意值都可以用一个20-bits的数字表示)。UTF-16将这20-bits分成两半,前10位映射在0xD800到0xDBFF,称为高位(H),后10位映射在0xDC00到0xDFFF,称为低位(L)。即该数字的前10位(bits)加上0xD800,就得到UTF-16四字节编码中的前两个字节;该数字的后10位(bits)加上0xDC00,就得到UTF-16四字节编码中的后两个字节。这意味着,一个辅助平面的字符,被拆成两个基本平面的字符表示。因此,当我们遇到两个字节,发现它的码点在0xD800到0xDBFF之间,就可以断定,紧跟在后面的两个字节的码点,应该在U+DC00到U+DFFF之间,这四个字节必须放在一起解读。

注意,0xD800到0xDFFF的区间恰好位于基本多文种平面的UTF-16 surrogoates区域。

以下为UTF-16对Unicode中文字符编码的示例:

这就是将U+22222按照UTF-16编码为字节序列D848DE22的过程。

附:Unicode的Code Point在线查询网址

3.UTF-32

对Unicode的每个字符按照码点值直接进行4个字节编码。编码顺序依赖BOM。这种方法有其优点,最重要的一点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始。虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。最主要的原因是太浪费存储空间。

UTF-8、UTF-16、UTF-32的对比如下:

字节序(Byte Order Mark,简称BOM):定义字符的比特流在存储或者传输时的顺序,采用大端(Big Endian)和小端(Little Endian)表示。UTF编码方式与其对应的BOM列表如下:

通常UTF-8编码不需要定义字节序,例如Java中默认UTF-8编码是UTF-8 without BOM。但也有按照大端方式定义,申明在比特流之前。而Windows的记事本默认将UTF-16LE称之为Unicode编码。

注:Windows内核采用UTF-16LE编码,以保证在不同地区字符串显示无区别!

四、代码页(Code Page)

代码页(Code Page)是字符集编码的别名。早期,代码页是IBM称呼电脑BIOS本身支持的字符集编码的名称。当时通用的操作系统都是命令行界面系统,这些操作系统直接使用BIOS供应的VGA功能来显示字符,操作系统的编码支持也就依靠BIOS的编码。现在这BIOS代码页被称为OEM代码页。图形操作系统解决了此问题,图形操作系统使用自己字符呈现引擎可以支持很多不同的字符集编码。

常见的代码页有:

我们在编程时,如果采用MBCS字符集,并且采用ANSI版本Windows字符串处理API,所有字符串赋值后存储的比特流是参照本地代码页的。只有采用UNICODE字符集,并且采用W版本Windows字符串处理API,字符串处理的比特流存储才是按照UTF-16LE的方式存储的。此时的程序在其他区域显示才不会出现乱码。

五、Unicode编程

实际上Windows从Win95开始内核就采用UTF-16LE(UCS-2LE),而通常简称这种编码方案为Unicode。Windows内部为了兼容字符串处理,会有两套版本Windows API,即ANSI版本和WideChar版本。而ANSI版本的API实现实际上是W版本API上面套了一层壳实现。通常非国际化的小型程序,字符集采用MBCS,字符串处理一切应该调用A版API。此时,字符串是按照char*的方式存储,通常中文占据2个字节,而拉丁文占据1个字节。根据上文描述的字符串赋值存储至exe的方式,此时字符串编码是参照本地CP_ACP代码页以二进制存入exe,在其他地区换用不同代码页的用户调用程序就可能显示为乱码。只有在程序制定字符集为UNICODE时,并且所有字符串处理API采用W版本,才能保证不同地区的用户获得的显示信息是一致的。

W版本函数调用字符串是按照wchar_t*方式存储的。常量字符串赋值时,需要添加L标识。即:

wchar_t pWSTR[40] = { L"hello world 中国" };

可以显著地发现W版本字符串与A版本字符串赋值方式有明显不同,并且数据类型也完全不同。为了方便地解决这一问题,微软定义了_T()宏。当采用MBCS字符集时,该宏不会对初始化的字符串有任何操作,而采用Unicode时,会自动在常量字符串前加上L标识。

并且,为了解决字符串数据类型在两种环境下定义不同的问题,微软重新定义了TCHAR的数据类型。

typedefcharTCHAR;//MBCS字符集typedefWCHARTCHAR;//Unicode字符集

因此,建议以后编程采用Unicode字符集,并且利用W版API函数处理字符串相关操作。如特殊情况只能指定数据类型为char*时,在利用WideCharToMultiByte和MultiByteToWideChar进行转换。调用转换函数时,第一个参数需要指定转换时原字符串采用的代码页,默认选择CP_ACP。

代码转换实现:Unicode、ANSI、UTF-8相互转换

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。