字符编码详解每一个程序员都不可避免的遇到字符编码的问题,特别是做Web开发的程序员,“乱码问题”一直是让人头疼的问题,也许您已经很少遇到“乱码”问题,然而,对解决乱码的方法的内在原理,您是否明白?本人作为一个程序员,在字符编码方面同样遇到不少问题,而且一直对各种编码懵懵懂懂、不清不楚;在工作中也曾经遇到一个很烦人的编码问题。
这两天在网上收集了大量编码方面的资料,对字符编码算是理解的比较清楚了。
下面把我认为比较重要的知识点记录下来,一方面方便以后复习;另一方面也希望给跟我一样懵懵懂懂的人一个参考。
不对或不妥之处,请批评指正。
在此之前,先了解一些有用概念:“字符集”、“字符编码”和“内码”。
1、字符集与字符编码字符是各种文字和符号的总称,包括各个国家文字、标点符号、图形符号、数字等。
字符集是多个字符的集合,字符集种类较多,每个字符集包含的字符个数不同,常见字符集有:ASCII字符集、ISO 8859字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。
计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。
编码(encoding)和字符集不同。
字符集只是字符的集合,不一定适合作网络传送、处理,有时须经编码(encode)后才能应用。
如Unicode可依不同需要以UTF-8、UTF-16、UTF-32等方式编码。
字符编码就是以二进制的数字来对应字符集的字符。
因此,对字符进行编码,是信息交流的技术基础。
使用哪些字符。
也就是说哪些汉字,字母和符号会被收入标准中。
所包含“字符”的集合就叫做“字符集”。
规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。
各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。
因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。
注意:Unicode字符集有多种编码方式,如UTF-8、UTF-16等;ASCII只有一种;大多数MBCS(包括GB2312)也只有一种。
2、什么是内码?2.1 维基百科的解释在计算机科学及相关领域当中,内码指的是“将资讯编码后,透过某种方式储存在特定记忆装置时,装置内部的编码形式”。
在不同的系统中,会有不同的内码。
在以往的英文系统中,内码为ASCII。
在繁体中文系统中,目前常用的内码为大五码(Big5)。
在简体中文系统中,内码则为国标码(国家标准代码:现在强制要求使用GB18030标准;较旧计算机仍然使用GB2312)。
而统一码(Unicode)则为另一常见内码。
2.2 百度百科的解释内码是指整机系统中使用的二进制字符编码,是沟通输入、输出与系统平台之间的交换码,通过内码可以达到通用和高效率传输文本的目的。
比如MS Word中所存储和调用的就是内码而非图形文字。
英文ASCII字符采用一个字节的内码表示,中文字符如国标字符集中,GB2312、GB12345、GB13000皆用双字节内码,GB18030(27,533汉字)双字节内码汉字为20,902个,其余6,631个汉字用四字节内码。
3、字符编码分类总结下面从计算机对多国语言支持的角度来总结字符编码。
3.1 ASCII编码以下来自“维基百科”:ASCII(American Standard Code for Information Interchange,美国信息互换标准代码)是基于拉丁字母的一套电脑编码系统。
它主要用于显示现代英语,而其扩展版本EASCII则可以勉强显示其他西欧语言。
它是现今最通用的单字节编码系统(但是有被UniCode追上的迹象),并等同于国际标准ISO/IEC 646。
ASCII第一次以规范标准的型态发表是在1967年,最后一次更新则是在1986年,至今为止共定义了128个字符;其中33个字符无法显示(这是以现今操作系统为依归,但在DOS 模式下可显示出一些诸如笑脸、扑克牌花式等8-bit符号),且这33个字符多数都已是陈废的控制字符。
控制字符的用途主要是用来操控已经处理过的文字。
在33个字符之外的是95个可显示的字符,包含用键盘敲下空白键所产生的空白字符也算1个可显示字符(显示为空白)。
ASCII表:见/zh-cn/ASCIIASCII缺点:ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如na?ve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。
而EASCII虽然解决了部份西欧语言的显示问题,但对更多其他语言依然无能为力。
因此现在的苹果电脑已经抛弃ASCII而转用Unicode。
最早的英文DOS操作系统的系统内码是:ASCII。
计算机这时候只支持英语,其他语言不能够在计算机存储和显示。
在该阶段,单字节字符串使用一个字节存放一个字符(SBCS,Single Byte Character System)。
如:"Bob123"占6个字节。
3.2 ANSI编码为使计算机支持更多语言,通常使用0x800~xFF范围的2个字节来表示1个字符。
比如:汉字'中' 在中文操作系统中,使用[0xD6,0xD0]这两个字节存储。
不同的国家和地区制定了不同的标准,由此产生了GB2312,BIG5,JIS等各自的编码标准。
这些使用2个字节来代表一个字符的各种汉字延伸编码方式,称为ANSI 编码。
在简体中文系统下,ANSI 编码代表GB2312 编码,在日文操作系统下,ANSI 编码代表JIS 编码。
不同ANSI 编码之间互不兼容,当信息在国际间交流时,无法将属于两种语言的文字,存储在同一段ANSI 编码的文本中。
中文DOS、中文/日文Windows 95/98时代系统内码使用的是ANSI编码(本地化)在使用ANSI编码支持多语言阶段,每个字符使用一个字节或多个字节来表示(MBCS,Multi-Byte Character System),因此,这种方式存放的字符也被称作多字节字符。
比如,"中文123" 在中文Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节。
在非Unicode 环境下,由于不同国家和地区采用的字符集不一致,很可能出现无法正常显示所有字符的情况。
微软公司使用了代码页(Codepage)转换表的技术来过渡性的部分解决这一问题,即通过指定的转换表将非Unicode 的字符编码转换为同一字符对应的系统内部使用的Unicode 编码。
可以在“语言与区域设置”中选择一个代码页作为非Unicode 编码所采用的默认编码方式,如936为简体中文GBK,950为正体中文Big5(皆指PC上使用的)。
在这种情况下,一些非英语的欧洲语言编写的软件和文档很可能出现乱码。
而将代码页设置为相应语言中文处理又会出现问题,这一情况无法避免。
从根本上说,完全采用统一编码才是解决之道,但目前尚无法做到这一点。
代码页技术现在广泛为各种平台所采用。
UTF-7 的代码页是65000,UTF-8 的代码页是65001。
3.3 Unicode编码为了使国际间信息交流更加方便,国际组织制定了UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。
Unicode字符集可以简写为UCS(Unicode Character Set)。
早期的unicodeUnicode标准有UCS-2、UCS-4的说法。
UCS-2用两个字节编码,UCS-4用4个字节编码。
在UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在UNICODE 字符集中的序号。
目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS,Double Byte Character System),因此,这种方式存放的字符也被称作宽字节字符。
比如,字符串"中文123" 在Windows 2000 下,内存中实际存放的是 5 个序号,一共10个字节。
Unicode字符集包含了各种语言中使用到的所有“字符”。
用来给UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。
4、常用编码规则4.1 单字节字符编码(1)编码标准:ISO-8859-1。
(2)说明:最简单的编码规则,每一个字节直接作为一个UNICODE 字符。
比如,[0xD6, 0xD0] 这两个字节,通过iso-8859-1 转化为字符串时,将直接得到[0x00D6, 0x00D0] 两个UNICODE 字符,即"?D"。
反之,将UNICODE 字符串通过iso-8859-1 转化为字节串时,只能正常转化0~255 范围的字符。
4.2 ANSI编码(1)GB2312, BIG5, Shift_JIS, ISO-8859-2。
(2)把UNICODE 字符串通过ANSI 编码转化为“字节串”时,根据各自编码的规定,一个UNICODE 字符可能转化成一个字节或多个字节。
反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。
比如,[0xD6, 0xD0] 这两个字节,通过GB2312 转化为字符串时,将得到[0x4E2D] 一个字符,即'中' 字。
“ANSI 编码”的特点:(1)这些“ANSI 编码标准”都只能处理各自语言范围之内的UNICODE 字符。
(2)“UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。
4.3 UNICODE编码(1)编码标准:UTF-8, UTF-16, UnicodeBig。
(2)与“ANSI 编码”类似的,把字符串通过UNICODE 编码转化成“字节串”时,一个UNICODE 字符可能转化成一个字节或多个字节。
与“ANSI 编码”不同的是:(1)这些“UNICODE 编码”能够处理所有的UNICODE 字符。
(2)“UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。
我们实际上没有必要去深究每一种编码具体把某一个字符编码成了哪几个字节,我们只需要知道“编码”的概念就是把“字符”转化成“字节”就可以了。
对于“UNICODE 编码”,由于它们是可以通过计算得到的,因此,在特殊的场合,我们可以去了解某一种“UNICODE 编码”是怎样的规则。