(个人理解+转载)ANSI/ASCII/UTF8/UNICODE/GB2312/UCS-2/UTF16-文本的编码格式

来源:互联网 发布:mac如何登陆远程桌面 编辑:程序博客网 时间:2024/05/16 19:37

参考文档:

http://baike.baidu.com/view/443268.htm?fromId=25492

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 

http://tech.idv2.com/2008/02/21/unicode-intro/

http://baike.baidu.com/view/185282.htm

http://baike.baidu.com/view/40801.htm

http://hilojack.sinaapp.com/?p=1291

 

个人学到的先附加在如下:

ASCII

1. ASCII码只表示128个字符,最前面一位为0. ASCII是计算机的一个基础存储格式。其他存储格式也都为它做了预留。

 

Unicode与UCS2\UTF8\UTF16

1. Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。UCS-2用两个字节编码,UCS-4用4个字节编码。

    我们通常Windows上见到的Unicode,不做说明的情况下,都是指的UCS-2这种字节编码。

2. Unicode UCS2使用两个字节来存储,是我们大多数情况都用到的uniocde方式,代码中使用也很方便(w_char)-双字节与它直接对应起来了。

3. UTF8使用的也非常普遍,它也是一种unicode的编码格式,它存在1/2/3/4个字节来表示一个文字。对于英文字符来说,使用空间非常小。 

4. UCS2与UTF16: UCS-2是UTF-16的子集,仅支持Unicode字符平面映射中的基本多文平面.占2个字节. 参考:http://hilojack.sinaapp.com/?p=1291

 

ANSI与GB2312

1. ANSI: unicode和ansi都是字符代码的一种表示形式,使用1-2字节表示一个字符。ANSI为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准。

2. GB2312是一种本地化的编码格式,是ANSI字符代码的一种编码格式,相同的值,在其他本地语言体系里,表达的东西是不同的。《信息交换用汉字编码字符集》是由中国国家标准总局1980年发布,1981年5月1日开始实施的一套国家标准,标准号是GB 2312—1980。

参考:http://baike.baidu.com/view/443268.htm?fromId=25492

 

 

 

 

下面为转载内容:地址如下

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html 

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

字符编码笔记:ASCII,Unicode和UTF-8

 

作者: 阮一峰

今天中午,我突然想搞清楚Unicode和UTF-8之间的关系,于是就开始在网上查资料。

结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚。

下面就是我的笔记,主要用来整理自己的思路。但是,我尽量试图写得通俗易懂,希望能对其他朋友有用。毕竟,字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识。

1. 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。

2、非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128--255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

中文编码的问题需要专文讨论,这篇笔记不涉及。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的Unicode和UTF-8是毫无关系的。

3.Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字"严"。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。

4. Unicode的问题

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字"严"的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别Unicode和ASCII?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果Unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了Unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示Unicode。2)Unicode在很长一段时间内无法推广,直到互联网的出现。

5.UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种Unicode的实现方式。其他实现方式还包括UTF-16(字符用两个字节或四个字节表示)和UTF-32(字符用四个字节表示),不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8是Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字"严"为例,演示如何实现UTF-8编码。

已知"严"的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此"严"的UTF-8编码需要三个字节,即格式是"1110xxxx 10xxxxxx 10xxxxxx"。然后,从"严"的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,"严"的UTF-8编码是"11100100 10111000 10100101",转换成十六进制就是E4B8A5。

6. Unicode与UTF-8之间的转换

通过上一节的例子,可以看到"严"的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击"文件"菜单中的"另存为"命令,会跳出一个对话框,在最底部有一个"编码"的下拉条。

bg2007102801.jpg

里面有四个选项:ANSI,Unicode,Unicode big endian 和 UTF-8。

1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

选择完"编码方式"后,点击"保存"按钮,文件的编码方式就立刻转换好了。

7. Little endian和Big endian

上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字"严"为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

因此,第一个字节在前,就是"大头方式"(Big endian),第二个字节在前就是"小头方式"(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

8. 实例

下面,举一个实例。

打开"记事本"程序Notepad.exe,新建一个文本文件,内容就是一个"严"字,依次采用ANSI,Unicode,Unicode big endian 和 UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit中的"十六进制功能",观察该文件的内部编码方式。

1)ANSI:文件的编码就是两个字节"D1 CF",这正是"严"的GB2312编码,这也暗示GB2312是采用大头方式存储的。

2)Unicode:编码是四个字节"FF FE 25 4E",其中"FF FE"表明是小头方式存储,真正的编码是4E25。

3)Unicode big endian:编码是四个字节"FE FF 4E 25",其中"FE FF"表明是大头方式存储。

4)UTF-8:编码是六个字节"EF BB BF E4 B8 A5",前三个字节"EF BB BF"表示这是UTF-8编码,后三个"E4B8A5"就是"严"的具体编码,它的存储顺序与编码顺序是一致的。

9. 延伸阅读

* The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(关于字符集的最基本知识)

* 谈谈Unicode编码

* RFC3629:UTF-8, a transformation format of ISO 10646(如果实现UTF-8的规定)

 

 

以下是转载内容,转载地址:

http://hilojack.sinaapp.com/?p=1291

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

04 五 13 字符编码入门

本文试图理清字符编码系统的整体结构.如有理解不对请指正.

字符编码

按照[现代的编码模型],字符编码的主要概念分为:有哪些字符(字符表)、它们的编号(编码字符集)、这些编号如何编码成一系列的“码元”(字符编码表)、这些码元如何组成八位字节流(字符编码方案).

Screenshot-from-2013-05-08-212532.png

字符表(Character Repotire)

一个系统所有抽象字符的集合,包括我们看得见的汉字/数字/符号和看不见的控制字符.unicode系统所使用的字符集是通用字符集UCS ,由ISO 10646所定义.

编码字符集(CCS:Coded Character Set)

将字符集C映射到非负整数(码位:编码字符的位置).如unicode字符平面映射.即完成对字符的编号.

unicode系统中的码位也叫unicode编码.

字符编码表(CEF:Caracter Encoding Form)

将码位转换成有限比特长度的整数值(码元/码值:字符编码的值)

在unicode系统中,其码位可被转换成8位串行的UTF-8,或者16位串行的UTF-16等等.也就说同一码位对应多个码值.
码元(Code Unit,也称“代码单元”)是指一个已编码的文本中具有最短的比特组合的单元。对于UTF-8来说,码元是8比特长;对于UTF-16来说,码元是16比特长;对于UTF-32来说,码元是32比特长。编码长度是码元的整数倍,如UTF-16的长度就是2字节/4字节(一对码元)

我们平时所说的UTF-8,UTF-16都处于字符编码表(CEF)的层面.

字符编码方案(CES:Caracter Encodeing Scheme)

定义如何将码值对应到8位组的串行,以便网络传输和文件存储.
这里有两个大背景:

  1. 对于多字节的UTF-16来说,windows是先读高字节再读低字节,而MAC则相反.为了标识字节顺序,就选择了一个字节序列标记(BOM:Byte Order Mark)来指定大端序(UTF-16 BE)和小端序(UTF-16).见UTF-16的编码模式
  2. 有些复杂的编码需要特别的方案:如ISO/IEC 2022需要使用转义串行,如SCSU、BOCU和Punycode需要压缩

在vim中,:%xxd 可查看相关字符的编码 :set fileencoding=**可对字符进行编码转换

unicode编码体系

unicode又名统一码、万国码、单一码、标准万国码

意义

因多语言环境的需要而诞生,它对应于ISO 10646通用字符集UCS,包括了其它所有字符集/已知语言的所有字符.

unicode与iso 10646

史上存在两个尝试创立单一字符集的组织:

  1. 国际标准化组织ISO——开发了ISO/IEC 10646项目
  2. 统一码联盟Unicode Consortium——开发了统一码项目

1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。于是,它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作.

到现在两个项目仍都存在,两者使用同一字符集,但二者本质上是不同的标准——unicode标准更为丰富,它额外定义了许多与字符相关的语义符号学,并且部分样例字形与iso 10646有显著区别。

unicode的编码和实现

一般,unicode编码系统分为编码方式(CCS)和实现方式(CEF/CES …).

Screenshot-from-2013-05-09-010033.png

unicode编码方式(CCS)

统一码(unicode)的编码方式使用的是通用字符集UCS. unicode字符的平面映射本质上就是CCS码位映射,即对字符的编号(ISO/IEC 10646-1所定义) (CCS)
这个码位就叫unicode编码.

  1. UCS-2:包含字符平面映射中的基本多文种平面,占16位,可表达2^16=65536个字符.2. UCS-4:其中已经定义了16个辅助平面.标准规定的UCS-4会占用32个字节,最高字节恒为0,可表达2^31个字符.

平面始末字符值中文名称英文名称0号平面U+0000 – U+FFFF基本多文种平面Basic Multilingual Plane, 简称 BMP1号平面U+10000 – U+1FFFF多文种补充平面Supplementary Multilingual Plane, 简称 SMP2号平面U+20000 – U+2FFFF表意文字补充平面Supplementary Ideographic Plane, 简称 SIP3号平面U+30000 – U+3FFFF表意文字第三平面(未正式使用[1])Tertiary Ideographic Plane, 简称 TIP4号平面

13号平面U+40000 – U+DFFFF(尚未使用) 14号平面U+E0000 – U+EFFFF特别用途补充平面Supplementary Special-purpose Plane, 简称 SSP15号平面U+F0000 – U+FFFFF保留作为私人使用区(A区)[2]Private Use Area-A, 简称 PUA-A16号平面U+100000 – U+10FFFF保留作为私人使用区(B区)[2]Private Use Area-B, 简称 PUA-B

实现方式(CEF/CES …)

在unicode编码体系中unicode码位转为实际存储的编码(码值)可以有不同实现方式.比如UTF8/UTF-16/UTF-32

在unicode体系中码位是唯一的,所以字符编码转换程序 在转码时 一般把码值转为unicode再转为其它的编码.

字节顺序标记(BOM)

BOM是用来标记字节序的. 在windows/mac中,UTF-16高低字节的存储顺序是不同的,为了以示区别,特别定义的大尾序和小尾序.同时在文件头部加入一个BOM头(Byte Order Mark).
对于UTF-8来说,它只是一个UTF-8编码记号(不建议使用,它会干扰很多程序的执行)

建议在编辑器中取消bom,比如在vim设置:set nobomb

编码表示 (十六进制)表示 (十进制)UTF-8EF BB BF239 187 191UTF-16(大端序)FE FF254 255UTF-16(小端序)FF FE255 254UTF-32(大端序)00 00 FE FF0 0 254 255UTF-32(小端序)FF FE 00 00255 254 0 0UTF-72B 2F 76和以下的一个字节:[ 38 | 39 | 2B | 2F ]43 47 118和以下的一个字节:[ 56 | 57 | 43 | 47 ]en:UTF-1F7 64 4C247 100 76en:UTF-EBCDICDD 73 66 73221 115 102 115en:Standard Compression Scheme for Unicode0E FE FF14 254 255en:BOCU-1FB EE 28 及可能跟随着FF251 238 40 及可能跟随着255GB-1803084 31 95 33132 49 149 51使用UTF-16编码的例子编码名称编码次序编码BOM朱,聿UTF-16LE小尾序 31 672C 007F 8069 D8 A5 DEUTF-16BE大尾序 67 3100 2C80 7FD8 69 DE A5UTF-16小尾序,包含BOMFF FE31 672C 007F 8069 D8 A5 DEUTF-16大尾序,包含BOMFE FF67 3100 2C80 7FD8 69 DE A5

UTF-16/UCS-2

UTF-16是Unicode字符集的一种转换方式(Unicode Transfomation Format),它把unicode码位转为16比特长的码元.
字符长度:2个字节(16比特),4个字节(一对16比特码元)

UCS-2是UTF-16的子集,仅支持Unicode字符平面映射中的基本多文平面.占2个字节.

字符编码表(CEF)

对于unicoe基本多文平面(0×0000~0xffff).UTF-16的编码为一个16比特:

UTF-16 == Unicode(0x0~0xffff) #不含(0xd800~0xdfff),这个区保留给UTF-16的前导代理和后导代理

对于uncide辅助平面(0×10000~0x10ffff),UTF-16的编码为一对16比特字符串,由前导代理(lead surrogates)和后导代理(trail surrogates)组成.

将unicode码元(0x10000~0x10ffff)减去0x10000得到20位比特:0x0~0xfffff,这20位比特分高10位A(0~0x3ff)和低10位B(0~0x3ff)UTF-16(lead surrogates) == A+0xd800 #值范围(0xd800~0xdbff)UTF-16(trail surrogates) == B+0xd800 #值范围(0xdc00~0xdfff)

UTF-16字符匹配正则

根据UTF-16的CEF规则,我们可以得到关于匹配UTF-16字符的正则伪代码(这个正则是无法执行的,可执行的正则可比这个可复杂多了):

'#[\x{0000}-\x{d7ff}]|[\x{e000}-\x{ffff}]|([\x{d800}-\x{dbff}][\x{dc00}-\x{dfff}])#'

UTF-8

utf8以8位为单元对UCS进行编码,编码会占用1~4字节.与utf16所编码的英文字符相比,它的编码长度减少一半.

UTF-8 字符编码表CEF

代码范围
十六进制标量值(scalar value)
二进制UTF-8
二进制/十六进制注释000000 – 00007F
128个代码00000000 00000000 0zzzzzzz0zzzzzzz(00-7F)ASCII字符范围,字节由零开始七个z七个z000080 – 0007FF
1920个代码00000000 00000yyy yyzzzzzz110yyyyy(C0-DF) 10zzzzzz(80-BF)第一个字节由110开始,接着的字节由10开始三个y;二个y;六个z五个y;六个z000800 – 00D7FF
00E000 – 00FFFF
61440个代码 [Note 1]00000000 xxxxyyyy yyzzzzzz1110xxxx(E0-EF) 10yyyyyy 10zzzzzz第一个字节由1110开始,接着的字节由10开始四个x;四个y;二个y;六个z四个x;六个y;六个z010000 – 10FFFF
1048576个代码000wwwxx xxxxyyyy yyzzzzzz11110www(F0-F7) 10xxxxxx 10yyyyyy 10zzzzzz将由11110开始,接着的字节由10开始三个w;二个x;四个x;四个y;二个y;六个z三个w;六个x;六个y;六个z

UTF-8优缺点

优点

  1. 保证搜索时一个字符的字符串不会出现在另一个字符的串里面.
  2. 兼容ASCII
  3. 抗干扰和稳定性好:一段两字节随机串行碰巧为合法的UTF-8而非ASCII的机率为32分1。对于三字节串行的机率为256分1,对更长的串行的机率就更低了

缺点

  1. 与UTF-16/gbk 想比,处理CJK字符串,编码长度不占优势

UTF-8正则匹配

当使用Perl时,可用以下的表达式测试页面是否使用了UTF-8编码:

m/\A(    [\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)*\z/x;

utf8_unicode_ci和utf8_general_ci区别

utf8_unicode_ci的最主要的特色是支持扩展,即当把一个字母看作与其它字母组合相等时。例如,在德语和一些其它语言中‘ß’等于‘ss’。

utf8_general_ci是一个遗留的 校对规则,不支持扩展。它仅能够在字符之间进行逐个比较。这意味着utf8_general_ci校对规则进行的比较速度很快,但是与使用utf8_unicode_ci的校对规则相比,比较正确性较差)。

其它UTF

UTF-7

UTF-7是一种可变长度的字符编码方式,用以将UTF-16字符以ASCII编码.也就是说用修改的Base64(Modified Base64)去编码UTF-16字符.

因为SMTP作为基本邮件传输标准,只允许传输ASCII字符,过去很多邮件传输都使用UTF-7.自从MIME扩展了电子邮件标准之后,SMTP支持了其它字符集.现在绝大多数邮件服务商都使用UTF-8/GB2312/GB18030作为邮件字符编码.

严格来说 UTF-7 不能算是 Unicode 所定义的字符集之一,较精确的来说, UTF-7 是提供了一种将 Unicode 转换为 7 比特 US-ASCII 字符的转换方式
Modified Base64 与Base64的主要区别是结尾不会有”=”

UTF-7由于安全性薄弱,已经走入历史.

Gmail中文用户默认外发邮件编码(content-type)是GB2312(可改为UTF-8).其传输编码(Content-Transfer-Encoding)会按数据最短的原则选择: quoted-printable/base64或者不用.
腾讯邮箱用户默认的外发邮件编码是gb18030(可改为UTF-8).其传输编码使用的是base64.

UTF-32

UTF-32 是一个 UCS-4 的子集,使用32-比特的码值,只在0到10FFFF的字码空间(百万个码位)

内容传输编码(Content-Transfer-Encoding)

CTE由MIME定义,用于email数据传输.包括“7bit”,“8bit”,“binary”,“quoted-printable”,“base64”.其中常见的传输码为Base64/quoted-printable

Base64

Base64不是字符编码方案,而是一种基于64个可打印字符来表示二进制数据的表示方法.6bit(2^6=64)为一单元,对应一个可打印的字符.三个字节有24个位元.对应4个Base64字符.

编码规则

将二进制流/文本流以每6bit为一单元,3个字节为一组.以6bit(2^6=64)的数字大小为位置对应以下字符中的一个:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

如果最后剩余2个或1个字节,按以下方式补0:

文本ManASCII编码7797110二进制位010011010110000101101110索引1922546Base64编码TWFu

最后,如果剩下两个字节,在编码结果后加1个“=”;如果最后剩下一个字节,编码结果后加2个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

Quoted-printable

可打印字符引用编码(Quoted-printable,或QP encoding).
它使用ASCII字符表示各种字符编码–以便能个7bit or 8bit 数据通路上传输数据.
此编码为是MIME中 content transfer encoding的一种,用于email.(与base64并列为两种基本的邮件传输编码)

编码规则

Quoted-printable以8bit为单位进行编码,规则如下:

一般的8bit编码为"="加两个十六进制值,如"\x7A"编码为"=7A"对于可打印的ascii码:0x21-0x7E("="号:0x3D除外),可用ASCII码直接表示但是,如果水平制表符和空格符出现在行尾,必须用OP编码表示为"=09"(tab)和"=20"(space)如果QP编码的数据每行长度超过76个字符,QP编码结果的每行结尾加一个软换行("=")

Gmail在发送以下字符时所使用的Content-Transfer-Econding正是QP,如果将其ContentType设置为:UTF-8.并发送邮件内容(“新”的utf8编码为\xe696b0):

新This is a test!If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy.

那么,经过QP编码后的邮件text/plain原文为:

=E6=96=B0This is a test!If you believe that truth=3Dbeauty, then surely mathematics is the most bea=utiful branch of philosophy.

你很可能看到的是这个(因为你的邮件文本编辑器做format字符时就在most处断行了,使得单行不超过76个字符):

=E6=96=B0This is a test!If you believe that truth=3Dbeauty, then surely mathematics is the mostbeautiful branch of philosophy.

还有一个text/html原文.

与base64相比,如果Content-Type编码与ASCII是兼容的,那么QP编码后的邮件原文中ASCII是可读的.

GB相关的编码

本小节主要归纳汉字相关的编码:GB2312,GBK,GB18030.他们的关系如下图:

Screenshot-from-2013-05-10-030342.png

如图所示,GB18030基本兼容GBK.

GB2312

GB2312,也叫GB2312-80,于1981年推出.

特点

  1. 收录6763个汉字

编码结构

先对汉字进行分区(得到的编码叫区位码).

  1. 01-09区为特殊符号。
  2. 16-55区为一级汉字,按拼音排序。
  3. 56-87区为二级汉字,按部首/笔画排序。

编码:
对于ascii(0×00-0x7f)保持不变.
对于汉字和符号,使用两个字节表示:“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上0xA0)

“啊”的区位码是0×1001,对应的gb2312就是0xb0a1

GBK

背景

因为原GB2312字符不足, 厂商微软利用GB 2312-80未使用的编码空间,收录GB 13000.1-93全部字符制定了GBK编码.

编码结构

对于GB2312字符保持不变,仅对Gb2312未使用的编码区进行了扩充.
对于双字节来说:第一字节的范围是81–FE(也就是不含80和FF),第二字节的一部分领域在40–7E,其他领域在80–FE.

GBK的编码范围范围第1字节第2字节编码数字数水准 GBK/1A1A9A1FE846717水准 GBK/2B0F7A1FE6,7686,763水准 GBK/381A040FE (7F除外)6,0806,080水准 GBK/4AAFE40A0 (7F除外)8,1608,160水准 GBK/5A8A940A0 (7F除外)192166用户定义AAAFA1FE564 用户定义F8FEA1FE658 用户定义A1A740A0 (7F除外)672 合计:  23,94021,886

按拼音排序

基于Gbk/Gb2312是按音序来编码的.可用此规则来对汉字进行拼音排序(以php为例)

//按拼音首字母排序$arr = array(    '北京'=>'010',    '成都'=>'028',);ukrsort($arr, 'cmp');var_dump($arr);/** * * 比较拼音首字母(基于字符是按拼音顺序编码) */function cmp(&$a, &$b) {    $a = iconv('utf-8', 'gbk', $a);    $a = $a[0];    $b = iconv('utf-8', 'gbk', $b);    $b = $b[0];    if ($a == $b) {        return 0;    }    return ($a > $b) ? 1 : -1;}function ukrsort(&$arr, $func) {    foreach ($arr as $k => $v) {        if (is_array($arr[$k])) {            ukrsort($arr[$k], $func);        }    }    uksort($arr, $func);}

也可以通过编码找到绝大部分汉字的拼音首字母(以php为例)

/** * 获取汉字拼音首字母(基于字符是按拼音顺序编码) */function getFirstLetter($str) {    $fchar = ord($str{0});    if ($fchar >= ord("A") and $fchar <= ord("z"))        return strtoupper($str{0});    if (!is_string($str)) {        var_dump($str);        return;    }    $s1 = @iconv("UTF-8", "gbk", $str);    $s2 = @iconv("gbk", "UTF-8", $s1);    if ($s2 == $str) {        $s = $s1;    } else {        $s = $str;    }    $asc = ord($s{0}) * 256 + ord($s{1}) ;    if ($asc >= 45217 and $asc <= 45252)        return "A";    if ($asc >= 45253 and $asc <= 45760)        return "B";    if ($asc >= 45761 and $asc <= 46317)        return "C";    if ($asc >= 46318 and $asc <= 46825)        return "D";    if ($asc >= 46826 and $asc <= 47009)        return "E";    if ($asc >= 47010 and $asc <= 47296)        return "F";    if ($asc >= 47297 and $asc <= 47613)        return "G";    if ($asc >= 47614 and $asc <= 48118)        return "I";    if ($asc >= 48119 and $asc <= 49061)        return "J";    if ($asc >= 49062 and $asc <= 49323)        return "K";    if ($asc >= 49324 and $asc <= 49895)        return "L";    if ($asc >= 49896 and $asc <= 50370)        return "M";    if ($asc >= 50371 and $asc <= 50613)        return "N";    if ($asc >= 50614 and $asc <= 50621)        return "O";    if ($asc >= 50622 and $asc <= 50905)        return "P";    if ($asc >= 50906 and $asc <= 51386)        return "Q";    if ($asc >= 51387 and $asc <= 51445)        return "R";    if ($asc >= 51446 and $asc <= 52217)        return "S";    if ($asc >= 52218 and $asc <= 52697)        return "T";    if ($asc >= 52698 and $asc <= 52979)        return "W";    if ($asc >= 52980 and $asc <= 53688)        return "X";    if ($asc >= 53689 and $asc <= 54480)        return "Y";    if ($asc >= 54481 and $asc <= 55289)        return "Z";    return null;}

GB18030

GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集(2005年发布).
有以下特点:

采用多字节编码,每个字可以由1个、2个或4个字节组成。
支持全部unicode(UCS)全部统一汉字.收录范围包含繁体汉字以及日韩汉字70244个
与GBK基本兼容,与GB 2312完全兼容

编码结构

  1. 单字节,其值从0到0x7F。
  2. 双字节,第一个字节的值从0×81到0xFE,第二个字节的值从0×40到0xFE(不包括0x7F)。
  3. 四字节,第一/三字节的值从0×81到0xFE,第二/四字节的值从0×30到0×39.

正则匹配

'#[\x00-\x7f]|[\x81-\xfe][\x40-0xfe]|([\x81-0xfe][\x30-\x39]){2}#'

参考

  1. 维基UCS
  2. 维基字符平面映射
  3. utf_bom
  4. 维基unicode
  5. 维基现代编码模型
  6. 维基UTF-16
  7. 维基UTF-8
  8. 维基GB2312
  9. 维基GBK
  10. 维基GB18030

 

原创粉丝点击