字符编码相关

来源:互联网 发布:淘宝电动车价格便宜 编辑:程序博客网 时间:2024/06/06 05:14

字符,字节,字符串

理解编码的关键,是要把字符的概念和字节的概念理解准确。这两个概念容易混淆,我们在此做一下区分:字符:人们使用的记号,抽象意义上的一个符号。  举例:'1', '中', 'a', '$', '¥', ……字节:计算机中存储数据的单元,一个8位的二进制数,是一个很具体的存储空间。   举例:0x01, 0x45, 0xFA, ……ANSI字符串:在内存中,如果“字符”是以 ANSI 编码形式存在的,一个字符可能使用一个字节或多个字节来表示,那么我们称这种字符串为 ANSI 字符串或者多字节字符串。   举例:"中文123"(占7字节)unicode字符串:在内存中,如果“字符”是以在 UNICODE 中的序号存在的,那么我们称这种字符串为 UNICODE 字符串或者宽字节字符串。  举例:L"中文123"(占10字节)由于不同ANSI编码所规定的标准是不相同的,因此,对于一个给定的多字节字符串,我们必须知道它采用的是哪一种编码规则,才能够知道它包含了哪些“字符”。而对于 UNICODE 字符串来说,不管在什么环境下,它所代表的“字符”内容总是不变的。

字符集,编码,解码

各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI编码标准所规定的内容包含两层含义:使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。单字节字符编码 ISO-8859-1(别名Latin-1)   最简单的编码规则,每一个字节直接作为一个 UNICODE 字符。比如,[0xD6, 0xD0] 这两个字节,通过 iso-8859-1 转化为字符串时,将直接得到 [0x00D6, 0x00D0] 两个 UNICODE 字符,即 "ÖÐ"。反之,将 UNICODE 字符串通过 iso-8859-1 转化为字节串时,只能正常转化 0~255 范围的字符。ANSI 编码 GB2312,BIG5,Shift_JIS,ISO-8859-2 …… 把 UNICODE 字符串通过 ANSI 编码转化为“字节串”时,根据各自编码的规定,一个 UNICODE 字符可能转化成一个字节或多个字节。反之,将字节串转化成字符串时,也可能多个字节转化成一个字符。比如,[0xD6, 0xD0] 这两个字节,通过 GB2312 转化为字符串时,将得到 [0x4E2D] 一个字符,即 '中' 字。“ANSI 编码”的特点:1. 这些“ANSI 编码标准”都只能处理各自语言范围之内的 UNICODE 字符。2. “UNICODE 字符”与“转换出来的字节”之间的关系是人为规定的。UNICODE 编码   UTF-8,UTF-16, UnicodeBig ……    与“ANSI 编码”类似的,把字符串通过 UNICODE 编码转化成“字节串”时,一个 UNICODE 字符可能转化成一个字节或多个字节。与“ANSI 编码”不同的是:1. 这些“UNICODE 编码”能够处理所有的 UNICODE 字符。2. “UNICODE 字符”与“转换出来的字节”之间是可以通过计算得到的。解码跟编码对应,用特定的规则将数字转换成原本代表的字符。

ASCII码

我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进 制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256 种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000到11111111。上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。ASCII码一共规定了128个字符的编码,比如空格"SPACE"是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

GB2312,BIG5,GBK

早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的BIG5。GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。从ASCII、GB2312到GBK,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK都属于双字节字符集 (DBCS)。

ANSI

ANSI(American National Standard Institite)在最初的时候,Internet上只有一种字符集——ANSI的ASCII字符集,它使用7bits来表示一个字符,总共表示128个字符,其中包括了英文字母、数字、标点符号等常用字符。之后,又进行扩展,使用8 bits表示一个字符,可以表示256个字符,主要在原来的7 bits字符集的基础上加入了一些特殊符号例如制表符。后来,由于各国语言的加入,ASCII已经不能满足信息交流的需要,因此,为了能够表示其它国家的文字,各国在ASCII的基础上制定了自己的字符集,这些从ANSI标准派生的字符集被习惯的统称为ANSI字符集,它们正式的名称应该是MBCS(Multi-Byte Chactacter System,即多字节字符系统)。这些派生字符集的特点是以ASCII 127 bits为基础,兼容ASCII 127,他们使用大于128的编码作为一个Leading Byte,紧跟在Leading Byte后的第二(甚至第三)个字符与Leading Byte一起作为实际的编码。这样的字符集有很多,我们常见的GB-2312就是其中之一。由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,提出了Unicode字符集,它固定使用16bits(两个字节、一个字)来表示一个字符,共可以表示65536个字符。将世界上几乎所有语言的常用字符收录其中,方便了信息交流。标准的Unicode称为UTF-16。后来为了双字节的Unicode能够在现存的处理单字节的系统上正确传输,出现了UTF-8,使用类似MBCS的方式对Unicode进行编码。注意UTF-8是编码,它属于Unicode字符集。Unicode字符集有多种编码形式,而ASCII只有一种,大多数MBCS(包括GB-2312)也只有一种。Unicode的最初目标,是用1个16位的编码来为超过65000字符提供映射。但这还不够,它不能覆盖全部历史上的文字,也不能解决传输的问题 (implantation head-ache's)尤其在那些基于网络的应用中。已有的软件必须做大量的工作来程序16位的数据。因此,Unicode用一些基本的保留字符制定了三套编码方式。它们分别是UTF-8,UTF-16和UTF-32。正如名字所示,在UTF-8中,字符是以8位序列来编码的,用一个或几个字节来表示一个字符。这种方式的最大好处,是UTF-8保留了ASCII字符的编码做为它的一部分,例如,在UTF-8和ASCII中,“A”的编码都是0x41.UTF-16和UTF-32分别是Unicode的16位和32位编码方式。考虑到最初的目的,通常说的Unicode就是指UTF-16。当然对于ANSI编码而言,0x00~0x7F(即十进制下的0到127)之间的字符,依旧是1个字节代表1个字符。这一点是ASNI编码与Unicode编码之间最大也最明显的区别。

内码,code page

计算机使用的缺省编码方式就是计算机的内码。目前Windows的内核已经支持Unicode字符集,这样在内核上可以支持全世界所有的语言文字。但是由于现有的大量程序和文档都采用了某种特定语言的编码,例如GBK,Windows不可能不支持现有的编码,而全部改用Unicode。Windows使用代码页(code page)来适应各个国家和地区。code page可以被理解为前面提到的内码。GBK对应的code page是CP936。微软也为GB18030定义了code page:CP54936。代码页(Code Page)是个古老的专业术语,据说是IBM公司首先使用的。代码页和字符集的含义基本相同,代码页规定了适用于特定地区的字符集合,和这些字符的编码。可以将代码页理解为字符和字节数据的映射表。Windows为自己支持的代码页都编了一个号码。例如代码页936就是简体中文 GBK,代码页950就是繁体中文 Big5。代码页的概念比较简单,就是一个字符编码方案。

什么是unicode?

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码(即一个整数),换句话说,统一码以一种抽象的方式(即数字)来处理字符,并将视觉上的演绎工作(例如字体大小、外观形状、字体形态、文体等)留给其他软件来处理,例如网页浏览器或是文字处理器。以满足跨语言、跨平台进行文本转换、处理的要求。

什么是UTF-8?

UTF是“Unicode Transformation Format”的缩写,可以翻译成Unicode字符集转换格式,即怎样将Unicode定义的数字转换成程序数据。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码。UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式如下:Unicode编码(十六进制) UTF-8 字节流(二进制)00000000 - 0000007F 0xxxxxxx00000080 - 000007FF 110xxxxx 10xxxxxx00000800 - 0000FFFF 1110xxxx 10xxxxxx 10xxxxxx00010000 - 001FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx00200000 - 03FFFFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx04000000 - 7FFFFFFF 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx单字节可编码的Unicode范围:\u0000~\u007F(0~127)双字节可编码的Unicode范围:\u0080~\u07FF(128~2047)三字节可编码的Unicode范围:\u0800~\uFFFF(2048~65535)四字节可编码的Unicode范围:\u10000~\u1FFFFF(65536~2097151)127、2047、66535、2097151这几个临界值怎么来的?因为UTF-8编码含有用于标识编码的0、110、1110等,所以1~4个字节的UTF-8编码有效位数分别为7、11、16、21。UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-    8编码的最大长度是6个字节。从上表可以看出,6字节模板有31个x,即可以容纳31位二进制数字。Unicode的最大码位0x7FFFFFFF也只有31位。例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110     1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx 10xxxxxx    10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011 0000,用这个比特流依次代替模板中的x,得到:11110000     10100000 10110000 10110000,即F0 A0 B0 B0。

大小端

为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于 8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于 大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。0000430: e684 6c4e 0100 1800 53ef 0100 0100 0000在大端模式下,前32位应该这样读: e6 84 6c 4e ( 假设int占4个字节)在小端模式下,前32位应该这样读: 4e 6c 84 e6( 假设int占4个字节)

utf-8没有字节序

UTF-8以字节为单元编码,相当于一串字节流,所以特别适合用于字符串的网络数据传输,不用考虑大小端问题。对于任何字符编码,编码单元的顺序是由编码方案指定的,与endian无关。例如GBK的编码单元是字节,用两个字节表示一个汉字。这两个字节的顺序是固定的,不受CPU字节序的影响。UTF-16的编码单元是word(双字节),word之间的顺序是编码方案指定的,word内部的字节排列才会受到endian的影响。UTF-8以字节为单元编码,CPU每次读取一个字节。UTF-16以两个字节为编码单元,CPU每次读取两个字节(就像读取一个short类型的整数,0000430: e684 6c4e,大端CPU读出来的是0xe6846c4e,小端CPU读出来的是0x4e6c84e6,显然0xe6846c4e和0x4e6c84e6代表两个字符,所以要指定BOM头,而UTF-8就不一样,每次只读取一个字节,所以不存在字节序的问题,注意不要把字节序和UTF-16两个字节的前后顺序搞混,后者是固定的,由编码规则定的。)当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。EF BB BF        UTF-8FE FF           UTF-16/UCS-2, little endianFF FE           UTF-16/UCS-2, big endianFF FE 00 00     UTF-32/UCS-4, little endian.00 00 FE FF    UTF-32/UCS-4, big-endian.

UCS和unicode

unicode2.0后基本和ISO 10646规范保持一致. 和unicode类似,iso组织也在做同样的事情,iso开展了 ISO/IEC 10646项目,名字叫“ Universal Multiple-Octet Coded Character Set”,简称UCS。后来,双方意识到时间上不需要2套通用的字符集,所以双方开始进行整合,到unicode2.0时,unicode的编码和ucs的编码都基本一致。unicode在编码上和UCS保持一致,在实现上有自己的规则,而UCS只定义了编码标准。unicode的实现形式上 有UTF-8,UTF-16,UTF-32,还有UTF-7等。UCS编码也有自己的格式:UCS-2和UCS-4等等。unicode的编码可以和UCS-2和UCS-4保持一致。但是又略有不同。UTF-16是UCS-2的扩展,UTF-32是UCS-4的子集。也就是说,UTF-16的实现上对code point的支持范围超过UCS-2,而UTF-32对code point的表示却又在UCS-4的范围之内。当前,Unicode深入人心,且UTF-8大行其道,UCS编码基本被等同于UTF-16,UTF-32了,所以目前UCS基本谈出人们的视野中。(Windows NT用的就是UCS-2)。

UCS-2 和 UTF-16

UTF-16和UCS-2都是Unicode的编码方式。Unicode使用一个确定的名字和一个叫做码位(code point)的整数来定义一个字符。例如©字符被命名为“copyright   sign”并且有一个值为U+00A9(0xA9,十进制169)的码位。Unicode的码空间从U+0000到U+10FFFF,共有1,112,064个码位(code point)可用来映射字符. Unicode的码空间可以划分为17个平面(plane),每个平面包含216(  65,536)个码位。每个平面的码位可表示为从U+xx0000到U+xxFFFF, 其中xx表示十六进制值从0016 到1016,共计17个平面。第一个Unicode平面(码位从U+0000至U+FFFF)包含了最常用的字符,该平面被称为基本多语言平面(Basic Multilingual    Plane),缩写为BMP。其他平面称为辅助平面(Supplementary Planes)。UCS-2 (2-byte Universal Character Set)是一种定长的编码方式,UCS-   2仅仅简单的使用一个16位码元来表示码位,也就是说在0到0xFFFF的码位范围内,它和UTF-16基本一致。UTF-16 (16-bit Unicode Transformation Format)是UCS-2的拓展,它可以表示BMP以为的字符。UTF-   16使用一个或者两个16位的码元来表示码位,这样就可以对0到0x10FFFF的码位进行编码。例如,在UCS-2和UTF-16中,BMP中的字符U+00A9 copyright sign(©)都被编码为0x00A9。但是在BMP之外的字符,例如��,只能用UTF-16进行编码,使用两个16为码元来表示:0xD834  0xDF06。这被称作代理对,值得注意的是一个代理对仅仅表示一个字符,而不是两个。UCS-2并没有代理对的概念,所以会将0xD834 0xDF06解释为两个字符。简单的说,UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-   2所指的是同一的意思。(严格的说这并不正确,因为在UTF-16中从U+D800到U+DFFF的码位不对应于任何字符,而在使用UCS-  2的时代,U+D800到U+DFFF内的值被占用。)但当引入辅助平面字符后,就称为UTF-16了。   一般认为Windows下以16bit表示的Unicode并不是UTF-16,而是UCS-2。但是这并不正确。UCS-2是一种编码格式,同时也是指以一一对应关系的Unicode实现。在UCS-2中只能表示U+0000到U+FFFF的BMP(Basic Multilingual Plane )     Unicode编码范围,属于定长的Unicode实现,而UTF-16是变长的,类似于UTF-  8的实现,但是由于其字节长度的增加,所以BMP部分也做到了一一对应,但是其通过两个双字节的组合可以做到表示全部Unicode,表示范围从U+0000 到 U+10FFFF。

http://bbs.chinaunix.net/thread-1680943-2-1.html
http://blog.csdn.net/ultrani/article/details/8432767
http://blog.163.com/lipse_huang/blog/static/191657545201261211330814/
http://www.fmddlmyy.cn/text6.html
http://www.fmddlmyy.cn/text16.html
http://www.fmddlmyy.cn/text17.html
http://www.regexlab.com/zh/encoding.htm

0 0
原创粉丝点击