字符集编码

1.基础知识

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项基本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为基础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

 

2.常用字符集和字符编码

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

 

2.1. ASCII字符集&编码

ASCIIAmerican Standard Code for Information Interchange美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语,而其扩展版本EASCII则可以勉强显示其他西欧语言。它是现今最通用的单字节编码系统(但是有被Unicode追上的迹象),并等同于国际标准ISO/IEC 646

ASCII字符集:主要包括控制字符(回车键、退格、换行键等);可显示字符(英文大小写字符、阿拉伯数字和西文符号)。

ASCII编码:将ASCII字符集转换为计算机可以接受的数字系统的数的规则。使用7位(bits)表示一个字符,共128字符;但是7位编码的字符集只能支持128个字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。ASCII字符集映射到数字编码规则如下图所示:

字符集编码_第1张图片

图1 ASCII编码表

字符集编码_第2张图片

图2 扩展ASCII编码表

ASCII的最大缺点是只能显示26个基本拉丁字母、阿拉伯数目字和英式标点符号,因此只能用于显示现代美国英语(而且在处理英语当中的外来词如naïve、café、élite等等时,所有重音符号都不得不去掉,即使这样做会违反拼写规则)。而EASCII虽然解决了部份西欧语言的显示问题,但对更多其他语言依然无能为力。因此现在的苹果电脑已经抛弃ASCII而转用Unicode。

 

2.2. GBXXXX字符集&编码

计算机发明之处及后面很长一段时间,只用应用于美国及西方一些发达国家,ASCII能够很好满足用户的需求。但是当天朝也有了计算机之后,为了显示中文,必须设计一套编码规则用于将汉字转换为计算机可以接受的数字系统的数。

天朝专家把那些127号之后的奇异符号们(即EASCII)取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

上述编码规则就是GB2312GB2312GB2312-80是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·基本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。下图是GB2312编码的开始部分(由于其非常庞大,只列举开始部分,具体可查看GB2312简体中文编码表):

字符集编码_第3张图片

图3 GB2312编码表的开始部分

由于GB 2312-80只收录6763个汉字,有不少汉字,如部分在GB 2312-80推出以后才简化的汉字(如"啰"),部分人名用字(如中国前总理朱镕基的"镕"字),台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。于是厂商微软利用GB 2312-80未使用的编码空间,收录GB 13000.1-93全部字符制定了GBK编码。根据微软资料,GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样),最早实现于Windows 95简体中文版。虽然GBK收录GB 13000.1-93的全部字符,但编码方式并不相同。GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为"技术规范指导性文件"。原始GB13000一直未被业界采用,后续国家标准GB18030技术上兼容GBK而非GB13000。

GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术 信息交换用汉字编码字符集 基本集的扩充》的修订版。与GB 2312-1980完全兼容,与GBK基本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。GB 18030主要有以下特点:

  • 与UTF-8相同,采用多字节编码,每个字可以由1个、2个或4个字节组成。
  • 编码空间庞大,最多可定义161万个字符。
  • 支持中国国内少数民族的文字,不需要动用造字区。
  • 汉字收录范围包含繁体汉字以及日韩汉字

    字符集编码_第4张图片

    图4 GB18030编码总体结构

    本规格的初版使中华人民共和国信息产业部电子工业标准化研究所起草,由国家质量技术监督局于2000年3月17日发布。现行版本为国家质量监督检验总局和中国国家标准化管理委员会于2005年11月8日发布,2006年5月1日实施。此规格为在中国境内所有软件产品支持的强制规格。

     

    2.3. BIG5字符集&编码

    Big5,又称为大五码五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录13,060个汉字。中文码分为内码及交换码两类,Big5属中文内码,知名的中文交换码有CCCII、CNS11643。Big5虽普及于台湾、香港与澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界标准。倚天中文系统、Windows等主要系统的字符集都是以Big5为基准,但厂商又各自增加不同的造字与造字区,派生成多种不同版本。2003年,Big5被收录到CNS11643中文标准交换码的附录当中,取得了较正式的地位。这个最新版本被称为Big5-2003。

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

    0x8140-0xA0FE

    保留给用户自定义字符(造字区)

    0xA140-0xA3BF

    标点符号希腊字母及特殊符号,包括在0xA259-0xA261,安放了九个计量用汉字:兙兛兞兝兡兣嗧瓩糎。

    0xA3C0-0xA3FE

    保留。此区没有开放作造字区用。

    0xA440-0xC67E

    常用汉字,先按笔划再按部首排序。

    0xC6A1-0xC8FE

    保留给用户自定义字符(造字区)

    0xC940-0xF9D5

    次常用汉字,亦是先按笔划再按部首排序。

    0xF9D6-0xFEFE

    保留给用户自定义字符(造字区)

    Unicode字符集&UTF编码

     

    3.伟大的创想Unicode

    ——不得不单独说Unicode

    像天朝一样,当计算机传到世界各个国家时,为了适合当地语言和字符,设计和实现类似GB232/GBK/GB18030/BIG5的编码方案。这样各搞一套,在本地使用没有问题,一旦出现在网络中,由于不兼容,互相访问就出现了乱码现象。

    为了解决这个问题,一个伟大的创想产生了——Unicode。Unicode编码系统为表达任意语言的任意字符而设计。它使用4字节的数字来表达每个字母、符号,或者表意文字(ideograph)。每个数字代表唯一的至少在某种语言中使用的符号。(并不是所有的数字都用上了,但是总数已经超过了65535,所以2个字节的数字是不够用的。)被几种语言共用的字符通常使用相同的数字来编码,除非存在一个在理的语源学(etymological)理由使不这样做。不考虑这种情况的话,每个字符对应一个数字,每个数字对应一个字符。即不存在二义性。不再需要记录"模式"了。U+0041总是代表'A',即使这种语言没有'A'这个字符。

    在计算机科学领域中,Unicode统一码万国码单一码标准万国码)是业界的一种标准,它可以使电脑得以体现世界上数十种文字的系统。Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式[1]对外发表。Unicode 还不断在扩增, 每个新版本插入更多新的字符。直至目前为止的第六版,Unicode 就已经包含了超过十万个字符(在2005年,Unicode 的第十万个字符被采纳且认可成为标准之一)、一组可用以作为视觉参考的代码图表、一套编码方法与一组标准字符编码、一套包含了上标字、下标字等字符特性的枚举等。Unicode 组织(The Unicode Consortium)是由一个非营利性的机构所运作,并主导 Unicode 的后续发展,其目标在于:将既有的字符编码方案以Unicode 编码方案来加以取代,特别是既有的方案在多语环境下,皆仅有有限的空间以及不兼容的问题。

    可以这样理解:Unicode是字符集,UTF-32/ UTF-16/ UTF-8是三种字符编码方案。

     

    3.1.UCS & UNICODE

    通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。历史上存在两个独立的尝试创立单一字符集的组织,即国际标准化组织(ISO)和多语言软件制造商组成的统一码联盟。前者开发的 ISO/IEC 10646 项目,后者开发的统一码项目。因此最初制定了不同的标准。

    1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode 2.0开始,Unicode采用了与ISO 10646-1相同的字库和字码;ISO也承诺,ISO 10646将不会替超出U+10FFFF的UCS-4编码赋值,以使得两者保持一致。两个项目仍都存在,并独立地公布各自的标准。但统一码联盟和ISO/IEC JTC1/SC2都同意保持两者标准的码表兼容,并紧密地共同调整任何未来的扩展。在发布的时候,Unicode一般都会采用有关字码最常见的字型,但ISO 10646一般都尽可能采用Century字型。

     

    3.2.UTF-32

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

    这种方法有其优点,最重要的一点就是可以在常数时间内定位字符串里的第N个字符,因为第N个字符从第4×Nth个字节开始。虽然每一个码位使用固定长定的字节看似方便,它并不如其它Unicode编码使用得广泛。

     

    3.3.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个字节。并且,如果我们假设某个字符串不包含任何星芒层中的字符,那么我们依然可以在常数时间内找到其中的第N个字符,直到它不成立为止这总是一个不错的推断。其编码方法是:

  • 如果字符编码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的编码。

    对于UTF-32和UTF-16编码方式还有一些其他不明显的缺点。不同的计算机系统会以不同的顺序保存字节。这意味着字符U+4E2D在UTF-16编码方式下可能被保存为4E 2D或者2D 4E,这取决于该系统使用的是大尾端(big-endian)还是小尾端(little-endian)。(对于UTF-32编码方式,则有更多种可能的字节排列。)只要文档没有离开你的计算机,它还是安全的——同一台电脑上的不同程序使用相同的字节顺序(byte order)。但是当我们需要在系统之间传输这个文档的时候,也许在万维网中,我们就需要一种方法来指示当前我们的字节是怎样存储的。不然的话,接收文档的计算机就无法知道这两个字节4E 2D表达的到底是U+4E2D还是U+2D4E。

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

     

    3.4.UTF-8

    UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码(定长码),也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字符的软件无须或只须做少部份修改,即可继续使用。因此,它逐渐成为电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。

    UTF-8使用一至四个字节为每个字符编码:

  1. 128个US-ASCII字符只需一个字节编码(Unicode范围由U+0000至U+007F)。
  2. 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要二个字节编码(Unicode范围由U+0080至U+07FF)。
  3. 其他基本多文种平面(BMP)中的字符(这包含了大部分常用字)使用三个字节编码。
  4. 其他极少使用的Unicode 辅助平面的字符使用四字节编码。

    在处理经常会用到的ASCII字符方面非常有效。在处理扩展的拉丁字符集方面也不比UTF-16差。对于中文字符来说,比UTF-32要好。同时,(在这一条上你得相信我,因为我不打算给你展示它的数学原理。)由位操作的天性使然,使用UTF-8不再存在字节顺序的问题了。一份以utf-8编码的文档在不同的计算机之间是一样的比特流。

    总体来说,在Unicode字符串中不可能由码点数量决定显示它所需要的长度,或者显示字符串之后在文本缓冲区中光标应该放置的位置;组合字符、变宽字体、不可打印字符和从右至左的文字都是其归因。所以尽管在UTF-8字符串中字符数量与码点数量的关系比UTF-32更为复杂,在实际中很少会遇到有不同的情形。

    优点

  • UTF-8是ASCII的一个超集。因为一个纯ASCII字符串也是一个合法的UTF-8字符串,所以现存的ASCII文本不需要转换。为传统的扩展ASCII字符集设计的软件通常可以不经修改或很少修改就能与UTF-8一起使用。
  • 使用标准的面向字节的排序例程对UTF-8排序将产生与基于Unicode代码点排序相同的结果。(尽管这只有有限的有用性,因为在任何特定语言或文化下都不太可能有仍可接受的文字排列顺序。)
  • UTF-8和UTF-16都是可扩展标记语言文档的标准编码。所有其它编码都必须通过显式或文本声明来指定。
  • 任何面向字节的字符串搜索算法都可以用于UTF-8的数据(只要输入仅由完整的UTF-8字符组成)。但是,对于包含字符记数的正则表达式或其它结构必须小心。
  • UTF-8字符串可以由一个简单的算法可靠地识别出来。就是,一个字符串在任何其它编码中表现为合法的UTF-8的可能性很低,并随字符串长度增长而减小。举例说,字符值C0,C1,F5至FF从来没有出现。为了更好的可靠性,可以使用正则表达式来统计非法过长和替代值(可以查看 W3 FAQ: Multilingual Forms上的验证UTF-8字符串的正则表达式)。

    缺点

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

     

    4.Accept-Charset/Accept-Encoding/Accept-Language/Content-Type/Content-Encoding/Content-Language

    在HTTP中,与字符集和字符编码相关的消息头是Accept-Charset/Content-Type,另外主区区分Accept-Charset/Accept-Encoding/Accept-Language/Content-Type/Content-Encoding/Content-Language:

    Accept-Charset:浏览器申明自己接收的字符集,这就是本文前面介绍的各种字符集和字符编码,如gb2312,utf-8(通常我们说Charset包括了相应的字符编码方案);

    Accept-Encoding:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate),(注意:这不是只字符编码);

    Accept-Language:浏览器申明自己接收的语言。语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等;

    Content-Type:WEB服务器告诉浏览器自己响应的对象的类型和字符集。例如:Content-Type: text/html; charset='gb2312'

    Content-Encoding:WEB服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如:Content-Encoding:gzip

    Content-Language:WEB服务器告诉浏览器自己响应的对象的语言。

-------------------------------------------------------------------------------------------------------------------------

从第一次开始写web程序,自己还有身边同事开发出现乱码情况基本都没有消停过。估计以后还会一样继续。这么些年,不断修修改改,也总结也归纳。程序从asp,asp.net,jsp,php,服务器从windows到linux,数据库也从sqlserver,mysql到oracle;它还是偶尔会出现。好了,我总结下我与它较量的一些收获吧。乱码都与字符集有关系,一切都从它开始说。

  • 什么是字符集,什么是字符编码,它做什么用?

字符(Charcter)是文字与符号的总称,包括文字、图形符号、数学符号等。而字符集是一组抽象的字符组合的集合。如:英文字符集,中文字符集,日文字符集等

什么是字符编码?

计算机只能存储0,1之类2进制数字,怎么样让它表示那么多各种各样的字符呢?就需要对各种字符指定一个数值的编码代号它就是字符编码。如:a这个字符,在ascii字符集编码表中对应的编号是97,而“中”在gb2312字符集中对应的编号是:16进制是D6D0 10进制是54992 。通过编号就可以找到计算机对应字符。不用将那么复杂的字符保存在计算机中,只需要保存它代号就好。字符集只是指定了一个集合中有哪些字符,而字符编码,是为这个集合中所有字符定义个编号,这就是字符集与编码区别所在。

如果我告诉别人,我这个字符是:gb2312字符集中编号是:54992或者是D6D0 ,无论那个程序都知道是”中”,如果有人听错了,把它弄成日文JIS字符集,然后他也去找编号是:54992对应的字符,却找到的是:”面“。

打了这个比方,相信大家找到原因了,同样如果把54992拿到ascii 码表找,就会得到对应:�� 两个不能打印字符了。

从上面看,当你拿到本来是gb2312编号,在不是它的字符集里面找就出现这样问题了。 其它,程序出现乱码也都是这个原因,找错了字符集表了.

  • 字符在计算机是怎么样存储的呢?

看了上面介绍,我想大家一定会说,如果所有文本的字符,都用它的符号存储在计算机里面,不就什么问题都么有吗?以前也这么想,后来一想啊,如果都存在计算机中,各种各样,怎么样表示呢?计算机处理01之类数字该多方便呢。

我们可以通过winhex实际来检查下,下面在简体中文下,将”中按照gb2312字符集编码保存。

字符集编码_第5张图片

以gb2312编码保存中文“中”,实际存储在计算机中是:D6D0,是“中”在字符集gb2312中的编号啦!

计算机中只保存字符在某字符集中对应的字符编号值,计算机只需要维持一份字符集清单,当读到这种编号值(编码),就在对应字符清单中找出该字符显示出来即可。字符大小颜色都是程序按照字符样式绘制而成的。

看个图:

字符集编码_第6张图片

计算机中只保存该字符在某字符集中对应的字符编号(也叫字符编码)

  • 怎么样读取文件并正确显示文件内容?

从上面例子知道字符实际以该字符在某字符集中字符编码存储与计算机磁盘中。

下面以“中国”为例(中文简体windows):

"中国" 保存编码 存储内容 记事本打开
ANSI D6D0 B9FA 正常
gb2312 D6D0 B9FA 正常
utf-8+BOM EFBBBF E4B8AD E59BBD 正常
utf-8 E4B8AD E59BBD 正常
unicode+BOM FFFE 2D4E FD56 正常
unicode 2D4E FD56 乱码(变成ANSI)
EUC-JP C3E6 B9F1 乱码(变成ANSI)
iso-8859-1 3F 3F 乱码(变成ANSI)

以下以:“abc”为例

"abc" 保存编码 存储内容 记事本打开
ANSI 61 62 63 正常
gb2312 61 62 63 正常
utf-8+BOM EFBBBF 61 62 63 正常
utf-8 61 62 63 正常
unicode+BOM FFFE 61 62 63 正常
unicode 61 62 63 正常(变成ANSI)
EUC-JP 61 62 63 正常(变成ANSI)
iso-8859-1 61 62 63 正常(变成ANSI)

从上面可以得到几点:

1、以某字符集存储字符时,它会在该字符集中搜索这个字符的位置(编号或编码),以这个编号(编码)保存在文件,如果所搜找不到该字符,一般会以:3F 3F保存(一定会出错)

2、当需要显示字符,从取文件中字符编码,如果没有指定字符集,会通过文件头(主要unicode字符集有特殊头标记)判断字符集,如果不是unicode字符集,默认都以ANSI字符集读取,用字符编码在该字符集中寻找对应字符,如果搜索到就正常显示,搜索不到就会显示乱码.

  • 常见问题字符疑问收集

什么是ANSI字符集?

这个不是固定字符集,如果在中文简体windows中,它代码字符集是gb2312,在繁体值代表是big5等等。

为什么英文字符不会出现乱码?

常见ascii码字符集是:128字符,对应编码值是:1-128 ,二进制表示是:00000001-01111111。它表示了所有常见英文数字,标点符号。其它字符集都是由ascii码字符集扩展而来,扩展了最高位由10000000开始,用多字节表示新的字符,基本都保留了:0xxxxxxx 开头128个基本字符,而且对应编码与ascii码相同。

这样,常见英文字符不论在那种字符集中,对应字符编码一致,存储编码也一样。读取时候无论用什么字符集读取,它所对应字符也一直。所有基本不会出现乱码情况。

读取软件能够识别存储文件的字符集吗?

由于目前各种字符集加起来有上百种,目前除了unicode字符集,定义的存储文件头,基本其它字符集只是给出了对应的字符编号值。因此,相同编号会出现在不同的字符集中,光从文件存储的编码值,是不能确定它的字符集的。如:gb2312字符集中,D6d0对应是“中”,而同样是:D6D0在ecu-jp 字符集中,对应是“面”

什么是bom头?

bom全称是:byte order mark,汉语意思是标记字节顺序码。只是出现在:unicode字符集中,只有unicode字符集,存储时候,要求指定编码,如果不指定,windows还会用默认的:ANSI读取。常见的bom头是:

 UTF-8 ║ EF BB BF UTF-16LE ║ FF FE (小尾) UTF-16BE ║ FE FF (大尾) UTF-32LE ║ FF FE 00 00 UTF-32BE ║ 00 00 FE FF


unicode与utf-8 、utf-16 utf-32是什么关系?

unicode(统一码、万国码、单一码)是一种字符集,Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。在Unicode中:汉字“字”对应的数字是23383。我们可以用:UTF-8、UTF-16、UTF-32表示这个数字,将数字23383存储在计算机中。UTF-8对应是:0xE6, 0xB1, 0x89(3个字节),UTF-16对应是:0x6c49(2个字节),UTF-32对应是:0x6c49(4个字节)。utf-8,utf-16,utf-32是unicode码一种实现形式,都是属于unicode编码。

unicode编码特点是什么?

unicode编码特点是,它定义了编码方式和存储实现方式。编码方式就是上面说的可以用,utf-8…utf-32表示,而存储实现方式,无论那种编码都知道了文件头(bom)。因此,可以通过这个特殊头来判断存储的文本文件使用那种字符集编码。
  
为什么utf-8编码不指定bom头(可以理解为文件头),软件任然可以正常判断出它字符集编码? 
这个问题估计很多朋友都会产生疑问,为什么utf-16不指定就读乱码,而utf-8可以。我们可以从下面的例子看下: utf-8是怎么样从unicode转换而来了。
 
 Unicode编码(16进制) ║ UTF-8 字节流(二进制) 000000 - 00007F ║ 0xxxxxxx 000080 - 0007FF ║ 110xxxxx 10xxxxxx 000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx 010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
从上面看,发现规律没有?第一个自己开头有几个”1”,后面就对应有几个10开头字节了。 这样我们都可以通过正则进行检测了.

[\x09\x0A\x0D\x20-\x7E] # ASCII
|[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16

由于它独特的编码存储特点,因此目前常见文本处理软件就能够自动分析出来。(windows记事本,editplus,notepad++等)

为什么bom头会产生乱码?

有bom头的存储或者字节流,它一定是unicode字符集编码。到底属于那一种(utf-8还是utf-16或是utf-32),通过头可以判断出来。由于已经说过utf-16,utf-32不指定bom头,解析程序默认就认为是ansi编码,出现乱码。而utf-8指定或者不指定程序都可判断知道对于的字符集编码。问题就出在这里,可能有的应用程序(ie6浏览器),它就认为如果utf-8编码,就不需要指定bom头,它可以自己判断,相反指定了bom头,它还会出现问题(因为它把头当utf-8解析出现乱码了)。这里不截图了,cnblogs里面谈这个比较多,目前ie6会出现问题。其它ie7+,firefox,chrome不会出现,会忽略掉bom头。统一解决办法是:存为utf-8编码是,不需要加入bom头,其它utf-16,utf-32加入。

通过程序运算gb2312编码能够自动转换为utf-8编码吗?

utf-8实际是unicode字符集表现方式。如果看了这2种字符集编码表就清楚了。它是2个独立字符集,相同汉字在2个字符集中所对应编号没有关系,而且汉字顺序也不同,gb2312先按照拼音后按照笔画排序,而unicode没有做相应规定。我们清楚知道,如果没有对应字符集映射关系表在手。通过直接程序进行运算是实现不了的。如果你手里有这2个字符集映射表。如:”字”utf-8是:0xE6, 0xB1, 0x89 ,对应unicode编码是:23383,然后拿23383,在unicode字符集寻找,发现是字符“字”,接着将“字”这个字符,拿到gb2312表中查询:0xCE,0xC4 因此转换结果是:0xE6,0xB1,0x89 ---> 0xCE,0xC4。

GB2312、GBK、gb18030、Big5是什么关系?

GB2312:1980年的GB2312一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

GBK: 汉字国标扩展码,基本上采用了原来GB2312-80所有的汉字及码位,并涵盖了原Unicode中所有的汉字20902,总共收录了883个符号, 21003个汉字及提供了1894个造字码位。包括港、台两种汉字字库.
 

GB18030-2000产生,在GBK汉字标准字符集继续扩展,GB18030是GBK的超集,也就是包含的字符要比GBK多,又增加了6351个字符,其中一部分为4字节字(four-byte encoding range)。增加了六种少数民族语言和一些四字节字。

Big5是中国台湾的,是繁体中文代表

GB18030兼容GBK兼容GB2312 ,相同常用汉字在GB2312编码表中字符编号(编码)与GBK,GB18030相同。如:”字“gb2312字符编码是:0xCE,0xC4 ,它在其它2个里面也是这个。因为GB2312只有7000多常用汉字,当出现繁体,古文时候就会出现问题,因此采用大集合的GB18030是个不错选择。

Big5与GB2312不能通过程序相互转换,需要有字符集映射关系表才能完成。

字符集是怎么样一个演变过程呢?

这个如果讲故事可以讲很久了。当计算机有美国人发明后,当时设计到字符输入,由于是英文字符,通过收集整理。它们形成了标准的ascii码(128) 字符集。8位,首位为0。由于不断普及,欧洲西方国家相应使用,发现有些特殊字符它们不能表示,如:λφ等。如是出来想法,想利用ascii码后128位,增加它们的字符。这样就出现了EASCII码。这些还是不能表示所有国家,想法语,俄语等有自己特殊字符。因此制定标准将后128位进行分片制定。制定出iso-8859系列字符集。

ISO/IEC 8859-1 (Latin-1) - 西欧语言
ISO/IEC 8859-2 (Latin-2) - 中欧语言
ISO/IEC 8859-3 (Latin-3) - 南欧语言。世界语也可用此字符集显示。
ISO/IEC 8859-4 (Latin-4) - 北欧语言
ISO/IEC 8859-5 (Cyrillic) - 斯拉夫语言
ISO/IEC 8859-6 (Arabic) - 阿拉伯语
ISO/IEC 8859-7 (Greek) - 希腊语
ISO/IEC 8859-8 (Hebrew) - 希伯来语(视觉顺序)
ISO 8859-8-I - 希伯来语(逻辑顺序)
ISO/IEC 8859-9(Latin-5 或 Turkish)- 它把Latin-1的冰岛语字母换走,加入土耳其语字母。
ISO/IEC 8859-10(Latin-6 或 Nordic)- 北日耳曼语支,用来代替Latin-4。
ISO/IEC 8859-11 (Thai) - 泰语,从泰国的 TIS620 标准字集演化而来。
ISO/IEC 8859-13(Latin-7 或 Baltic Rim)- 波罗的语族
ISO/IEC 8859-14(Latin-8 或 Celtic)- 凯尔特语族
ISO/IEC 8859-15 (Latin-9) - 西欧语言,加入Latin-1欠缺的芬兰语字母和大写法语重音字母,以及欧元(€)符号。
ISO/IEC 8859-16 (Latin-10) - 东南欧语言。主要供罗马尼亚语使用,并加入欧元符号。

这些在一段时间,可以解决西方国家常见字符。当后来电脑在中日韩等国家普及时候,象中国常见汉字有7000多个,扩展128个空位,完全不够。因此,需要用多个字节表示。后来就定,第一个字节,第一位如果是1,后面还有一个字节与之一起表示一个字符。如果是0,就对应ascii码。这样就形成了国内的gb2312,后来还是不够表示繁体中文,加入了:gbk,最后是gb18030,但是,这样全世界各个国家还是用它们自己字符集进行表示。没有一个统一的大字符集,能够表示全球所有字符。直到unicode出现,它的设计最多可以表示100多万个字符。全球所有字符都可以收纳在其中。写出的程序,不用经常进行各种编码转换。就可以让世界上所有国家可以阅读对应字符文字。

什么是代码页,它与字符集有什么关系?

大家在指定网页程序语言生活,还记得cp936表示中文代码页(code page)。那么它与我们说的gbk字符集有什么关系呢?代码页是字符集编码的别名,也有人称"内码表"。早期,代码页是IBM称呼电脑BIOS本身支持的字符集编码的名称。

常见字符集与代码页直接映射是:

cp charset

932 — 日文
936 — 简体中文(GBK)
949 — 韩文
950 — 繁体中文(大五码)
1200 — UCS-2LE Unicode 小端序
1201 — UCS-2BE Unicode 大端序
65001 — UTF-8 Unicode

936就是我们的gbk字符编码集。

CJK字符集是什么?

cjk代号意思是:汉语(Chinese)、日语(Japanese)、韩语(Korean)。也就是包含这3国语言的字符集。包含这3个国家常见的汉字,一共有2万多个。

所有软件都会默认是:ANSI字符集吗?

不同程序默认读取字符集不同,上面举例是记事本默认是这样的。在php里面会以:iso-8859-1读取。 jsp程序,java默认字符集也是:iso-8859-1。

为什么很多软件程序编译过程使用是:iso-8859-1字符集?

由于我们通过应用程序书写的软件是用各种字符集编码保存在磁盘中。如果中文默认是用gbk。保存于磁盘中,默认以字节码保存,是否有无中文,每个字码值在:1-256。这些刚好可以用iso-8859-1扩展单字节字符集。因为,它是存储最小单元。在程序语言里面,不会用中文作变量,函数等名称。那些对应都是常见ascii码。而中文用字注释,或者一些常量中。在编译时候不会影响到语法问题。它会以原来字节码保持原样。在读取时候,只需要用对应的字符集编码读出,就能得到对应中文字符。


你可能感兴趣的:(字符集编码)