Chinaunix首页 | 论坛 | 博客
  • 博客访问: 435407
  • 博文数量: 117
  • 博客积分: 3003
  • 博客等级: 中校
  • 技术积分: 1221
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-16 14:11
文章分类

全部博文(117)

文章存档

2011年(7)

2010年(110)

我的朋友

分类: LINUX

2011-03-08 23:24:45

字符集与编码问题小结
2009-07-15 19:57

写在前面

一直想整理一点文字编码相关的东西,却由于能力不够,始终不知道如何下手。看到论坛中编码一再被提起,终于决定尝试着整理一下。

--2010.05.30

编码的引入

我们都了解,计算机只能存储2进制,也是就010100...,而无法存储“abc...”。当有人想把文字存储到计算机时,编码的故事就开始了...

既然计算机只能,只能存放二进制,那么我们就把“abc...”通过某种方式变成二进制不就解决了么?

比如,

  • a 用 01000001 表示,
  • b用 01000010 表示,
  • ... (注:以下为了书写简单,采用0x41 这种形式表示 01000001)

哎,等等,为什么要用 0x41 表示 a 呢,如果有人用下面的方式怎么办?

  • a 用 0x81 表示,
  • b 用 0x82
  • ...

ASCII

有人用 0x41 代表a,有人用 0x81 表示。语言不通,不同的计算机无法交流。美国人很早发现了这种问题,为便于交流指定了编码标准,于是有了:

ASCII (American Standard Code for Information)

  • ASCII码是7位编码,但由于计算机基本处理单位为字节(1byte = 8bit),所以一般仍以一个字节来存放一个ASCII字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为0。
  • ASCII被定为国际标准之后的代号为ISO-646

ISO-8859-*

ASCII 解决了美国人的问题,但很快,其他国家发现了这个编码不能满足自己国家的需要。法国、德国等国家暂且不说,英国都发现ASCII有问题:英镑符号“£”去哪儿了?现在好了,

既想与ASCII兼容,有要添加ASCII没有的文字符号,怎么办?扩展一下吧!

由于ASCII码只使用了7个二进制位,也就是说一个字节可以表示的256个数字中,它仅使用了0~127这128个码位,剩下的128个码位便可以用来做扩展,用来表示一些特定语言所独有的字符

因此对这多余的128个码位的不同扩展,就形成了一系列ISO-8859-*的标准。例如为英语作了专门扩展的字符集编码标准编号为ISO-8859-1,也叫做Latin-1。

ISO-8859-* (*代表1~11,13~16)共15个编码方案,解决了 拉丁字母的语言(主要是欧洲国家的语言),使用西里尔字母的东欧语言、希腊语、泰语、现代阿拉伯语、希伯来语等。

* 这些编码方案在当时解决了这些国家的问题,但不同的编码如同军阀割据,同一势力范围内交流没问题,但不能普遍通用。比如 \xA3 在使用 Latin-1 的国家看来,是英镑符号“£”,而在使用 Latin-2的国家看来,却是另一个符号 “Ł”。而且无法在一个文件内同时出现这两个符号。这个问题的解决,需要unicode。

ISO-2022 与 EUC

ISO-8859-* 解决了多数语言的编码问题,可是,汉语、日语及韩语字数众多,无法用单一个8位字符来表达,也就是无法通过类似 ISO-8859-*的方式解决。于是有了 ISO-2022

ISO-2022提供了这样一种技术,它能在一种字符编码中支持多种字符集,可以用8位或16位来表示一个文字(字符),是一种变长的编码,这样,就能表示中日韩的字符了。该编码还有个显著的特点,就是所有的字节都是以0开始。

ISO-2022 在日本用的比较普遍,在中国反倒是很少使用。尽管如此,还是用中文的 ISO-2022-CN 简单说一下:

在继续之前,我们先提一下GB2312:GB2312 中规定了汉字的区位码,同时指定 ISO-2022 (等同GB 2311) 为包装方式。

汉字“文”字在46区36位,用 ISO 2022 包装时,字节序列是:

  •  $ ) A  <0x4E> <0x44> 
  • 是字节 0x1b

  • 是字节 0x0e,表示脱离普通 ASCII 编码模式,进入特殊编码模式(这儿指 GB2312 编码)

  • 是字节 0x0f,表示返回普通 ASCII 编码模式

  • 第一字节 0x4E 是在区号 46 的基础上加上 32,以避开 ASCII 的控制符区(<32)

  • 第二字节 0x44 是在位号 36 的基础上加上 32,以避开 ASCII 的控制符区(<32)

前面说了,ISO-2022 在国内很少使用,那么国内用的什么编码方案呢?

这就是 EUC-CN:

EUC (Extended Unix Code),是一个主要用于日文、韩文、简体中文 的多字节编码系统,它基于ISO-2020标准。它使用了一些兼容于ISO-2022区位码的94x94编码表,把每个区位加上0xA0来表示,以便兼容于ASCII。

今天通常说的 GB2312 编码都是指 EUC 包装的 GB2312 编码。

EUC-GB2312 与区位码的关系:

  • 第1字节 = 区码 + 32 + 0x80
  • 第2字节 = 位码 + 32 + 0x80
  • “文”字的 EUC-GB2312 编码是 0xCE 0xC4

Unicode

Unicode是由于传统的字符编码方式的局限性而产生的,例如:

  • ISO 8859所定义的字符虽然在不同的国家中广泛地使用,可是在不同国家间却经常出现不相容的情况。
  • 很多传统的编码方式都具有一个共通的问题,即其容许电脑进行双语环境式的处理(通常是ASCII以及其本地语言),但却无法同时支援多语言环境式的处理(比如同是处理中文和日文)。

于是一个将所有国家所有语种的所有文字进行统一编码的方案开始了...

Unicode与UCS

1980年代,有两个组织分别开始开发适用于各国语言的通用码,但不久他们便发现了对方的存在。

  • Unicode 组织,由多家计算机软件公司,还包括一些出版行业的公司共同发起的。采用16位编码空间
  • ISO-10646 项目组,Universal Character Set(UCS),采用31位编码空间

ISO与Unicode是两个不同的组织,因此最初制定了不同的标准;但自从unicode2.0开 始,unicode采用了与ISO 10646-1相同的字库和字码,ISO也承诺ISO10646将不会给超出0×10FFFF的UCS-4编码赋值,使得两者保持一致。最终,两者统一了 抽象字符集(即任何一个在Unicode中存在的字符,在UCS中也存在),且最靠前的65535个字符也统一了字符的编码。

编码字符集与字符编码

在传统意义上,没有字符集和编码的区分,比如GB2312、Latin1等都是既指代字符集又指代编码方案。

  • 编码字符集 Coded Character Set
  • 字符编码 Character Encoding

按照惯例,人们认为字符集和字符编码是同义词,但现代的编码方案 Unicode,没有遵循这种惯例。

Unicode 是一个字符集合,它给集合中的每个字符都指定一了个代号。

当我们要把这个代号存到计算机中时,需要把它变成一个字节的序列。不同的变换方式引入了 UTF

  • Unicode 和 UCS 两者指的都是编码字符集,而不是字符编码。
  • UTF: Unicode Transformation Format 是字符编码

UTF

  • UTF-8, 8bit编码, ASCII不作变换, 其他字符做变长编码, 每个字符1-6 byte. 通常作为外码. 有以下优点:
    • 与CPU字节顺序无关, 可以在不同平台之间交流
    • 容错能力高, 任何一个字节损坏后, 最多只会导致一个编码码位损失, 不会链锁错误(如GB码错一个字节就会整行乱码)
    • UTF-8用一个字节 表示ASCI字符,用两个字节表示西欧字符,用三个字符表示亚洲的大部分字符。
  • UTF-16, 16bit编码, 是变长码,
    • UTF-16是 unicode的preferred encoding。
    • UCS-2与UTF-16在对前65536个字符的处理上也完全相同,唯一的区别只在于 UCS-2 不支持surrogate pair机制,即是说,UCS-2只能对前65536个字符编码,对其后的字符毫无办法。
    • UTF-16是windows平台上主要使用的编码方案
  • UTF-32, 仅使用了unicode范围(0到0×10FFFF)的32位编码, 相当于UCS-4的子集.
    • Linux下使用的UTF-32方案。

UTF 还涉及到字节序的问题。字节顺序标记(Byte Order Mark, 简称BOM)出现在Unicode流开端,说明编码类型。BOM是一个有点小聪明的想法。下面是常用的BOM:

UTF-16 big endian

FE FF

UTF-16 little endian

FF FE

UTF-32 bign endian

00 00 FE FF

UTF-32 little endian

FF FE 00 00

UTF-8 little endian

EF BB BF

GB18030

  • GB 18030: Unicode 的GBK扩展版本, 覆盖了所有unicode编码, 地位等同于UTF-8, UTF-16, 是一种unicode编码形式. 变长编码, 用单字节/双字节/4字节对字符编码
  • GB18030向下兼容GB2312/GBK.
  • GB 18030是中国所有非手持/嵌入式计算机系统的强制实施标准.

其他

GBK

GBK (Microsoft Code Page 936)

相传是微软公司在 EUC-GB2312 的基础上扩充了 Unicode 1.1 (GB13000.1-93) 而来, 最早出现于 Windows 95。没有对应的国家标准,只有一个《全国信息技术标准化技术 委员会 汉字内码扩展规范(GBK) 1.0》。

  • 第1字节 0x80-0xFE
  • 第2字节 0x40-0xFE
  • 这样一来,GBK (CP936) 就已经打破了 EUC 的规范。

base64

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一

Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。

HZ

将 EUC-GB2312 的各字节最高位去掉,再在前后分别加上转义字符,例如“文”:

~{ <0x4E> <0x44> ~}
阅读(1808) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~