1、 仁人教育Unicode 字符集(简称为 UCS)1名称的由来Unicode 字符集 编码是( Universal Multiple-Octet Coded Character Set) 通用多八位编码字符集的简称,支持世界上超过 650 种语言的国际字符集。Unicode 允许在同一服务器上混合使用不同语言组的不同语言。它是由一个名为 Unicode 学术学会(Unicode Consortium)的机构制订的字符编码系统,支持现今世界各种不同语言的书面文本的交换、处理及显示。该编码于 1990 年开始研发,1994 年正式公布,最新版本是 2005 年 3 月 31 日的 Unicode
2、4.1.0。Unicode 是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。2编码方法Unicode 标准始终使用十六进制数字,而且在书写时在前面加上前缀“U+”,例如字母“A”的编码为 004116 。所以“A” 的编码书写为“U+0041”。3UTF-8 编码UTF-8 是 Unicode 的其中一个使用方式。 UTF 是 Unicode Translation Format,即把 Unicode 转做某种格式的意思。UTF-8 便于不同的计算机之间使用网络传输不同语言和编码的文字,使得双字节的 Unic
3、ode 能够在现存的处理单字节的系统上正确传输。仁人教育UTF-8 使用可变长度字节来储存 Unicode 字符,例如 ASCII 字母继续使用 1 字节储存,重音文字、希腊字母或西里尔字母等使用 2 字节来储存,而常用的汉字就要使用 3 字节。辅助平面字符则使用 4字节。4UTF-16 和 UTF-32 编码UTF-32、UTF-16 和 UTF-8 是 Unicode 标准的编码字符集的字符编码方案,UTF-16 使用一个或两个未分配的 16 位代码单元的序列对 Unicode 代码点进行编码;UTF-32 即将每一个 Unicode 代码点表示为相同值的 32 位整数通过一个问题了解 u
4、nicode 编码问题:使用 Windows 记事本的“另存为”,可以在ANSI、GBK、Unicode、Unicode big endian 和 UTF-8 这几种编码方式间相互转换。同样是 txt 文件,Windows 怎样识别编码方式的呢?我很早前就发现 Unicode、Unicode big endian 和 UTF-8 编码的 txt文件的开头会多出几个字节,分别是 FF、FE (Unicode ),FE、FF(Unicode big endian),EF 、BB、BF(UTF-8) 。但这些标记是基于什么标准呢?答案:ANSI 字符集定义:ASCII 字符集,以及由此派生并兼容的字
5、符集,如:GB2312 ,正式的名称为 MBCS(Multi-Byte Chactacter System,多字节字符系统) ,通常也称为 ANSI 字符集。 仁人教育UNICODE 与 UTF8、 UTF16 由于每种语言都制定了自己的字符集,导致最后存在的各种字符集实在太多,在国际交流中要经常转换字符集非常不便。因此,产生了 Unicode 字符集,它固定使用 16 bits(两个字节) 来表示一个字符,共可以表示 65536 个字符 标准的 Unicode 称为 UTF-16(UTF:UCS Transformation Format )。后来为了双字节的 Unicode 能够在现存的处
6、理单字节的系统上正确传输,出现了 UTF-8,使用类似 MBCS 的方式对 Unicode 进行编码。(Unicode 字符集有多种编码形式 ) 例如“连通“两个字的 Unicode 标准编码 UTF-16 (big endian)为:DE 8F 1A 90 而其 UTF-8 编码为:E8 BF 9E E9 80 9A 当一个软件打开一个文本时,它要做的第一件事是决定这个文本究竟是使用哪种字符集的哪种编码保存的。软件一般采用三种方式来决定文本的字符集和编码: 检测文件头标识,提示用户选择,根据一定的规则猜测 最标准的途径是检测文本最开头的几个字节,开头字节 Charset/encoding,如
7、下表: EF BB BF : UTF-8 FF FE : UTF-16/UCS-2, little endian FE FF : UTF-16/UCS-2, big endian FF FE 00 00 : UTF-32/UCS-4, little endian. 仁人教育00 00 FE FF : UTF-32/UCS-4, big-endian. 1、big endian 和 little endianbig endian 和 little endian 是 CPU 处理多字节数的不同方式。例如“汉” 字的 Unicode 编码是 6C49。那么写到文件里时,究竟是将 6C写在前面,还是将
8、 49 写在前面?如果将 6C 写在前面,就是 big endian。还是将 49 写在前面,就是 little endian。“endian”这个词出自 格列佛游记 。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。我们一般将 endian 翻译成“字节序”,将 big endian 和 little endian称作“大尾”和“小尾”。2、字符编码、内码,顺带介绍 汉字编码字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用 7 位
9、的 ASCII 编码,为了处理汉字,程序员设计了用于简体中文的 GB2312 和用于繁体中文的big5。GB2312(1980 年)一共收录了 7445 个字符,包括 6763 个汉字和682 个其它符号。汉字区的内码范围高字节从 B0-F7,低字节从A1-FE,占用的码位是 72*94=6768。其中有 5 个空位是 D7FA-D7FE。GB2312 支持的汉字太少。 1995 年的汉字扩展规范 GBK1.0 收录了21886 个符号,它分为汉字区和图形符号区。汉字区包括 21003 个仁人教育字符。2000 年的 GB18030 是取代 GBK1.0 的正式国家标准。该标准收录了 2748
10、4 个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的 PC 平台必须支持 GB18030,对嵌入式产品暂不作要求。所以手机、MP3 一般只支持 GB2312。从 ASCII、GB2312 、GBK 到 GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为 0。按照程序员的称呼,GB2312、GBK 到 GB18030 都属于双字节字符集 (DBCS)。有的中文 Windows 的缺省内码还是 GBK,可以通过 GB18030 升级包升级到
11、GB18030。不过 GB18030 相对 GBK 增加的字符,普通人是很难用到的,通常我们还是用 GBK 指代中文 Windows 内码。这里还有一些细节:GB2312 的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上 A0。在 DBCS 中, GB 内码的存储格式始终是 big endian,即高位在前。GB2312 的两个字节的最高位都是 1。但符合这个条件的码位只有128*128=16384 个。所以 GBK 和 GB18030 的低字节最高位都可能不是 1。不过这不影响 DBCS 字符流的解析:在读取 DBCS 字符流时,只要遇到高位为 1 的字节,就可以将下两个字节
12、作为一个双字节编码,而不用管低字节的高位是什么。仁人教育3、Unicode、UCS 和 UTF(UCS Transformation Format)前面提到从 ASCII、GB2312 、GBK 到 GB18030 的编码方法是向下兼容的。而 Unicode 只与 ASCII 兼容(更准确地说,是与 ISO-8859-1 兼容) ,与 GB 码不兼容。例如“汉”字的 Unicode 编码是6C49,而 GB 码是 BABA。UCS 规定了怎么用多个字节表示各种文字。而怎样传输这些编码,是由 UTF(UCS Transformation Format)规范规定的!常见的 UTF规范包括 UTF-
13、8、UTF-7、UTF-16。4、UTF 的字节序和 BOMUTF-8 以字节为编码单元,没有字节序的问题。UTF-16 以两个字节为编码单元,在解释一个 UTF-16 文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的 Unicode 编码是 594E, “乙”的 Unicode 编码是 4E59。如果我们收到 UTF-16 字节流“594E”,那么这是“奎”还是“乙”?Unicode 规范中推荐的标记字节顺序的方法是 BOM。BOM 不是“Bill Of Material”的 BOM 表,而是 Byte Order Mark。BOM 是一个有点小聪明的想法:在 UCS 编码中有
14、一个叫做 “ZERO WIDTH NO-BREAK SPACE“的字符,它的编码是 FEFF。而 FFFE 在 UCS 中是不存在的字符,所以不应该出现在实际传输中。UCS 规范建议我们在传输字节流前,先传输字符“ZERO WIDTH NO-BREAK SPACE“。这样如果接收者收到 FEFF,就表明这个字节流是 Big-Endian 的;仁人教育如果收到 FFFE,就表明这个字节流是 Little-Endian 的。因此字符“ZERO WIDTH NO-BREAK SPACE“又被称作 BOM。UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。字符“ZERO W
15、IDTH NO-BREAK SPACE“的 UTF-8 编码是 EF BB BF(读者可以用我们前面介绍的编码方法验证一下) 。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8 编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的。写到这里对编码有了大致的了解了,就可以理解网上一些文章的话了,比如有一篇很流行的文章URL 编码与 SQL 注射里面有一段是这么说的:其实 url 编码就是一个字符 ascii 码的十六进制。不过稍微有些变动,需要在前面加上“%”。比如“” ,它的 ascii 码是 92,92 的十六进制是 5c,所以 “”的 url 编
16、码就是 %5c。那么汉字的 url 编码呢?很简单,看例子:“胡” 的 ascii 码是-17670,十六进制是 BAFA,url 编码是“%BA%FA”。呵呵,知道怎么转换的了吧。这得从 ASCII 说起,扩展的 ASCII 字符集采用 8bit255 个字符显然不够用,于是各个国家纷纷制定了自己的文字编码规范,其中中文的文字编码规范叫做“GB2312-80”(就是 GB2312),它是和 ASCII兼容的一种编码规范,其实就是用 扩展 ASCII 没有真正标准化这一点,把一个中文字符用两个扩展 ASCII 字符来表示。文中说的的中文 ASCII 码实际上就是简体中文的编码 2312GB!它
17、把 ASCII 又扩仁人教育充了一个字节,由于高位的第一位是 0,所以会出现负数的形式,url 编码就是将汉字的这个 GB2312 编码转化成 UTF-8 的编码并且每 8 位即一个字节前面加上%符号表示。那为何 UTF-8 是进行网络的规范传输编码呢?在 Unicode 里,所有的字符被一视同仁。汉字不再使用“ 两个扩展ASCII”,而是使用“1 个 Unicode”,注意,现在的汉字是“一个字符”了,于是,拆字、统计字数这些问题也就自然而然的解决了。但是,这个世界不是理想的,不可能在一夜之间所有的系统都使用Unicode 来处理字符,所以 Unicode 在诞生之日,就必须考虑一个严峻的问
18、题:和 ASCII 字符集之间的不兼容问题。 我们知道,ASCII 字符是单个字节的,比如“A”的 ASCII 是 65。而Unicode 是双字节的,比如“A” 的 Unicode 是 0065,这就造成了一个非常大的问题:以前处理 ASCII 的那套机制不能被用来处理Unicode 了 另一个更加严重的问题是,C 语言使用0作为字符串结尾,而Unicode 里恰恰有很多字符都有一个字节为 0,这样一来,C 语言的字符串函数将无法正常处理 Unicode,除非把世界上所有用 C 写的程序以及他们所用的函数库全部换掉 于是,比 Unicode 更伟大的东东诞生了,之所以说它更伟大是因为它让 U
19、nicode 不再存在于纸上,而是真实的存在于我们大家的电脑中。那就是:UTF UTF= UCS Transformation Format UCS 转换格式,它是将仁人教育Unicode 编码规则和计算机的实际编码对应起来的一个规则。现在流行的 UTF 有 2 种:UTF-8 和 UTF-16 其中 UTF-16 和上面提到的 Unicode 本身的编码规范是一致的,这里不多说了。而 UTF-8 不同,它定义了一种“ 区间规则”,这种规则可以和 ASCII 编码保持最大程度的兼容,这样做的好处是压缩了字符在西欧一些国家的内存消耗,减少了不必要的资源浪费,这在实际应用中是非常有必要的。 UTF
20、-8 有点类似于 Haffman 编码,它将 Unicode 编码为:00000000-0000007F 的字符,用单个字节来表示; 00000080-000007FF 的字符用两个字节表示 (中文的编码范围)00000800-0000FFFF 的字符用 3 字节表示 因为目前为止 Unicode-16 规范没有指定 FFFF 以上的字符,所以UTF-8 最多是使用 3 个字节来表示一个字符。但理论上来说,UTF-8 最多需要用 6 字节表示一个字符。 在 UTF-8 里,英文字符仍然跟 ASCII 编码一样,因此原先的函数库可以继续使用。而中文的编码范围是在 0080-07FF 之间,因此是
21、 2个字节表示(但这两个字节和 GB 编码的两个字节是不同的) 。看看编码之多:ANSI,AscII,GB2312,GBK,BIG5,GB18030,Unicode,UCS(就是unicode)Utf-8,utf-16,utf-32 整整 10 种编码,算是够复杂了可是这还仅仅是个开始,应用方面变化无穷,不过现在看到这些东西起码再不会头大了!呼呼仁人教育哦,漏了一个加密的 base64 编码。什么是 Base64? 按照 RFC2045 的定义, Base64 被定义为:Base64 内容传送编码被设计用来把任意序列的 8 位字节描述为一种不易被人直接识别的形式。 (The Base64 Co
22、ntent-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.) 为什么要使用 Base64?在设计这个编码的时候,我想设计人员最主要考虑了 3 个问题: 1.是否加密? 2.加密算法复杂程度和效率 3.如何处理传输? 加密是肯定的,但是加密的目的不是让用户发送非常安全的Email。这种加密方式主要就是“防君子不防小人”。即达到一眼望去完全看不出内容即可。 基于这个目的加密算法的复杂程度和效率也就不能太大和太低。
23、和上一个理由类似,MIME 协议等用于发送 Email 的协议解决的是如何收发 Email,而并不是如何安全的收发 Email。因此算法的复杂程度要小,效率要高,否则因为发送 Email 而大量占用资源,路就有点走歪了。 但是,如果是基于以上两点,那么我们使用最简单的恺撒法即可,为什么 Base64 看起来要比恺撒法复杂呢?这是因为在 Email 的传仁人教育送过程中,由于历史原因,Email 只被允许传送 ASCII 字符,即一个 8 位字节的低 7 位。因此,如果您发送了一封带有非 ASCII 字符(即字节的最高位是 1)的 Email 通过有“历史问题 ”的网关时就可能会出现问题。网关可能会把最高位置为 0!很明显,问题就这样产生了!因此,为了能够正常的传送 Email,这个问题就必须考虑!所以,单单靠改变字母的位置的恺撒之类的方案也就不行了。关于这一点可以参考 RFC2046。 基于以上的一些主要原因产生了 Base64 编码。