字符集与字符编码
字符集与字符编码(理解ASCII、ANSI、UTF-8、Unicode,解决各种乱码问题)
相信很多同学也像我一样,经常在工作和学习中遇到字符编码的疑惑或者受到乱码的困扰,每次遇到问题都需要去学习了解不同的名词含义甚至需要深入学习不同的编码机制,不胜烦恼,所以今天我将自己的学习心得记录下来,希望能简单明了地描述字符集和字符编码。
1 多种字符集与多种编码共存的原因
- 首先必须要认识到一点,不论是简单的字符还是更复杂的图像、声音、视频等都是用于描述现实世界的信息,只是信息的表现形式不同,可以理解为对现实世界抽象的结果。例如,远古时期的象形文字最初就像是将客观事物的外观画出来用于描述该客观事物,随着人类对世界的认知越来越深入,象形文字在信息传递过程中显得极为不便,于是文字就向着更为抽象且简单化、符合人类认知习惯的方向发展和转变,在这个过程中因为各个不同地区的人对世界的理解和认识不同,所以会形成不同体系的语言和文字,如中国使用汉语体系、日本使用日语体系、英美使用英语体系,这是造成多种字符集共存的历史和根源原因,这是一个无可避免的客观历史问题。
- 每一种不同的语言体系都有严格的标准和约定来保证语言的规范性,这样在不同的人使用文字进行沟通时,只要遵循相同的标准和约定就可以有效地实现信息传递。就像小时候学语文时常用的新华字典,其实就是国家为了规范人民在文字、发音、含义上的共识而采取的有效教育决策。但是新华字典只规范了中国的汉语言体系,并未制定其他国家语言体系的标准(因为这是别人国家的事情),于是不同的国家就制定了自己国家语言体系的文字规范与标准。如美国最早制定了ASCII字符集,包含了英文字符、数字字符、常用的图形字符及控制字符,中国制定了GB2312字符集,包含了ASCII字符集以及常用的汉字字符,日本制定了Shift_JIS字符集,包含了全形及半形拉丁字母、平假名、片假名、符号及日语汉字。
- 为了能够在计算机中表示和处理字符信息,就必须对每个字符进行编码,实现字符到二进制之间的一一映射,通常这个映射需要分两个步骤来完成:第一步,给字符集中的每一个字符都赋予一个独一无二的数值编号,将字符映射为数值,如汉字使用区位码;第二步,通过一定的机制将数值编号映射为二进制形式,将数值映射为特定形式的二进制编码。以上整个过程就称为字符集编码,字符集和字符集编码虽然是配套使用,但字符集仅仅相当于字符的容器,是概念上的容纳,如果想要在计算机中使用字符集中的字符则必要要进一步对字符集中的每个字符进行编码,映射成为特定的二进制形式。
2 字符集
2.1 ASCII字符集
2.1.1 标准ASCII字符集
- ASCII (American Standard Code for Information Interchange):美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符 。
- 在英语中,用128个符号编码便可以表示所有,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。
- 但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel(ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是一样的,不一样的只是128–255的这一段。
2.1.2 ANSI
- 为使计算机支持更多语言,通常使用 0x00–0x7F范围的1 个字节来表示 1个英文字符,超出此范围的使用0x80–0xFFFF来编码,即扩展的ASCII编码。不同的国家和地区制定了不同的标准,由此产生了GB2312、GBK、GB18030、Big5、Shift_JIS等各自的编码标准,这些使用多个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码,美国国家标准学会(AMERICAN NATIONAL STANDARDS INSTITUTE: ANSI)。在简体中文Windows操作系统中,ANSI 编码代表GB2312编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI 编码代表 JIS编码。
- 可以理解为ANSI是使用一个字节来表示标准ASCII字符集,使用两个或者更多字节来表示本地字符集,其中地方语言字符集在不同国家有不同含义,通常与国家制定的字符集标准兼容,例如我国的简体中文字符集GB2312。
0x00–0x7F0x80–0xFFFFASCII字符集地方语言字符集2.2 汉字字符集
2.2.1 GB2312
- GB2312或GB2312-80是一个简体中文字符集的中国国家标准,全称为《信息交换用汉字编码字符集–基本集》,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于大陆;新加坡等地也采用此编码。几乎所有的中文系统和国际化的软件都支持GB2312。
- GB2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时,GB2312收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄罗斯语西里尔字母在内的682个全形字符。
2.2.2 GBK
- GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖99.75%的使用频率。但对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了GB2312的扩展版字符集GBK及GB18030汉字字符集的出现。
- GBK全称《汉字内码扩展规范》,发布于1995年,只是 “技术规范指导性文件”,并不属于国家标准。其中的K是汉语拼音 Kuo Zhan(扩展)中的“Kuo”的首字母,意思是GB2312的扩展版,在GB2312的基础上将字符扩展到两万多个,完全兼容 GB2312。
2.2.3 GB18030
- GB18030,全称《信息技术中文编码字符集》,是中华人民共和国国家标准所规定的变长多字节字符集,其对GB2312-1980完全向后兼容,与GBK基本向后兼容,并支持Unicode(GB 13000)的所有码位,GB18030-2005共收录汉字70,244个。
- 2022年7月19日,国家市场监督管理总局(国家标准化管理委员会)批准《信息技术 中文编码字符集》强制性国家标准GB 18030-2022,2023年8月1日实施。
- 总结一下就是,GB2312、GBK和GB18030都是包含了标准ASCII字符集和汉字字符集的中国标准字符集,区别是从GB2312到GB18030其容纳的字符数量越来越丰富,但又都是向前兼容的,其关系可以用下图来描述。
2.3 Unicode字符集
不同的地区和国家使用不同的字符编码,使得不同国家之间使用计算机进行交流变得很困难,经常会出现乱码的问题,比如:对于同一个二进制数据,不同的编码会解析出不同的字符。例如,\xD6D0使用GB2312字符集解析时对应汉字“中”,但使用SHIFT_JIS解析时对应日文“ヨミ”,可以使用在线转码工具进行验证。于是,使用一种统一的规则对全世界所有国家和地区的字符进行统一编码成为了互联网发展过程中亟需解决的重要问题。
Unicode,中文又称万国码、国际码、统一码、单一码,它为每种语言中的每个字符设定了统一而且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。在Unicode环境下,不会再有语言的编码冲突,在同屏下,可以显示任何语言的内容,Unicode是围绕全球通用字符集(Universal Character Set,UCS)的标准来发展的,当前使用两个字节来编码,称为UCS-2,若后期出现字符增加两个字节不够用时则使用4个字节来编码,称为UCS-4。
3 字符编码
每一种字符集都必须配套有特定的编码规则,将字符的编号映射成为二进制编码,从而实现计算机中的表示、存储和计算。
3.1 ASCII字符集的编码
使用7位二进制来表示一个ASCII字符,共计表示128个字符,包含了大小写英文字母、数字、可视字符以及若干控制字符,其编码的取值范围为0x00–0x7F。
3.2 GB系列字符集的编码
ASCII字符集部分使用0x00–0x7F表示,与ASCII编码兼容,汉字部分使用区位码+0xA0A0表示,使汉字编码与ASCII编码不出现重叠。
3.3 Unicode字符集的编码
- 虽然GB系列字符集采用区位码来表示汉字的编号,但Unicode采用了完全不同的方式,Unicode中每个汉字的编号与GB字符集中的编号完全不同,他给每个汉字定义了一个独一无二的Unicode编号。
- 例如,汉字“中”的在GB系列字符集中被映射到区码为54(0x36),位码为48(0x30)的位置上,所以其区位码为0x3630,加上0xA0A0得到最终编码0xD6D0;而在Unicode字符集中,“中”字被映射到编号0x4E2D位置上,其编码方式有UTF-8、UTF-16和UTF-32三种,对0x4E2D编码后的结果均不相同。
- UTF-8(8位元,Universal Character Set/Unicode Transformation Format)是针对Unicode的一种可变长度字符编码,分成单字节、双字节、三字节、四字节模式,理论上可以最多到4个字节长,然而16位BMP字符最多只用到3字节长,Bigendian UCS-4字节串的排列顺序是预定的,字节0xFE和0xFF在UTF-8编码中从未用到。UTF-8 的编码规则: (1)对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的, 所以 UTF-8 能兼容 ASCII 编码。 (2)对于 n 字节的符号( n > 1),第一个字节的前 n 位都设为 1,第 n + 1 位设为 0,后面字节的前两位一律设为 10 。剩下的没有提及的二进制位,全部为这个符号的Unicode 码。
- 例如:英文字符’a’对应的Unicode字符集编号为0x61,属于0x00–0x7F之间,所以采用单字节编码,0110 0001。汉字字符“中”对应的Unicode字符集编号为0x4E2D,处于0x800–0xFFFF之间,所以需要采用三字节编码,依据规则(2)n=3,第一个字节的前3位都设为1,第4位设为0,所以第一个字节为 1110 xxxx,后面还有两个字节均以10开头,所以都为 10xx xxxx,最终的形式为(字节从高到低): 1110 xxxx 10xx xxxx 10xx xxxx,将 4E2D 的二进制形式 0100111000101101 从左到右依次填充编码中的 x 即可得到最终的编码结果: 1110 0100 1011 1000 10101101,即 0xE4 0xB8 0xAD。
- UTF-16 也是一种变长字符编码, 这种编码方式比较特殊, 它将字符编码成 2 字节 或者 4 字节。UTF-16 的编码规则: (1)对于Unicode编号小于 0x10000的字符,使用2字节存储,不进行任何转换,直接存储Unicode编号,如汉字“中”的Unicode编号为0x4E2D,则其编码就为 0x4E2D,但多字节数值存在字节序问题,默认使用小端存储,其存储顺序为:0x2D 0x4E。如英文字符“a”的Unicode编号为 0x0061,则其存储顺序为:0x61 0x00。 (2)对于Unicode编号在0x10000–0x10FFFF之间的字符,使用4字节存储,前两个字节的高6位固定为110110,后两个字节的高6位固定为110111,前后部分各剩余10位二进制表示符号的Unicode编号减去 0x10000 的结果。 例如:线性标志符号的Unicode编号为 U+10600,减去 0x10000后得 0x 00600,0000 0000 0110 0000 0000,按照(2)中的规则,共计4个字节,其形式为110110xx xxxxxxxx 110111xx xxxxxxxx,使用0x00600的二进制填充形式中的x即可得到 11011000 00000001 11011110 00000000,即 0xD8 0x01 0xDE 0x00。 (3)Unicode编号大于 0x10FFFF的字符无法使用 UTF-16编码表示。UTF-32的编码规则:
- UTF-32采用固定4个字节长度的编码,足以容纳Unicode中的所有字符,无须任何转换,直接存储Unicode编号即可。
4 Editplus编码案例
Editplus文本编辑器支持各种编码格式,这里仅对简体中文用户经常遇到的字符编码情况进行验证。
4.1 英文字符编码
4.2 简体中文字符编码
参考:
[1] https://zhuanlan.zhihu.com/p/427488961
[2] https://blog.csdn.net/Deft_MKJing/article/details/79460485
[3] https://blog.csdn.net/Deft_MKJing/article/details/79460485
[4] https://www.toolhelper.cn/EncodeDecode/EncodeDecode
版权归原作者 iamjixiaoyu 所有, 如有侵权,请联系我们删除。