关于unicode,mbcs,utf8,charset,encoding等相关概念的说明

好像第一次遇到跟字符集有关的问题大概应该是在7年前,第一次写java,老是会出现编码转换的问题,动不动就乱码,基本上,本着实用主义的态度,以盲人摸象的手法,总算是可以解决问题的。这些年来,不停的会遇到编码方面的问题,随着每一次解决问题,都感受多揭开了一点笼罩在这一堆乱七八糟的东西上面的迷雾,然而,直到去年年中,我仍然没有彻底搞明白这堆乱七八糟的名词和概念之间,到底是怎样的关系。 去年年中开始的项目,须要用c++来处理文档,不可避免的遇到了编码转换的问题,在用c++处理的时候,我不得不仔细的探究在不一样的编码转换的时候究竟发生了什么事情,终于,总算是搞明白了这些东西。下面,我会试着解释一下这些概念自己以及他们之间的关系,部分解释来自维基百科或者msdn,版权不属于我。 ANSI/ASCII : 由美国国家标准委员会指定的是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其余西欧语言。它是现今最通用的单字节编码系统,并等同于国际标准ISO 646。(from wiki) MBCS : 多字节字符集,是一种替代 Unicode 以支持没法用单字节表示的字符集(如日文和中文)的方法。为国际市场编程时应考虑使用 Unicode 或 MBCS,或使程序可以经过更改开关来生成支持两种字符集之一的程序。最多见的 MBCS 实现是双字节字符集 (DBCS)。通常来讲,Visual C++(尤为是 MFC)彻底支持 DBCS。(from msdn) UNICODE : 是业界的一种标准,它可使电脑得以呈现世界上数十种的文字系统。Unicode 是基于通用字元集(Universal Character Set)的标准来发展,而且同时也以书本的形式(The Unicode Standard,目前第五版由Addison-Wesley Professional出版,ISBN-10: 0321480910)对外发表。Unicode 包含了超过十万个字元(在西元 2005 年, Unicode 的第十万个字元被采纳且承认成为标准之一)、一组可用以做为视觉参考的代码图表、一套编码方法与一组标准字元编码、一套包含了上标字、下标字等字元特性的列举等。(from wiki) UTF-8 : 英文全称为8-bit UCS/Unicode Transformation Format,是针对Unicode 的一种可变长度字元编码。从名称能够看出,UTF-8是专为UCS/Unicode设计的传输格式。它能够用来表示 Unicode 标准中的任何字元,并且其编码串流中的第一个位元组仍与 ASCII 兼容,令原来处理 ASCII 字符的软件无需或只做少许改动后,即可继续使用。所以,它逐渐成为电子邮件、网页及其余储存或传送文字的应用中,优先采用的编码。(from wiki) 基本的名词解释完了,如今来仔细的解释一下Charset/Encoding(字符集/编码)。Charset很容易和Encoding搞混,也是刚开始接触字符编码问题是最容易被晕掉的概念。字符集的概念,实际上,包含两个方面,一个,是字符的集合,即所谓的Charset,一个是编码方案,也就是所谓的Encoding。所谓字符的集合,意即一个字符集,定义了它所包含的全部符号,这实际上正是字符集名字的真正含义。也就是说,狭义上的字符集,并不包含编码方案,它仅仅是定义了哪些符号属于这个字符集。可是,一般来讲,一个字符集并不只仅定义字符集合,同时,它还为每一个符号定义一个二进制编码,因此,当咱们提到GB2312的时候,咱们并不只仅是指GB2312字符集,同时,也指明了编码方案是GB2312,即Charset= GB2312,Encoding=GB2312,这说明,咱们的文档中不包含GB2312之外的字符,而它们的二进制编码采用GB2312规定的编码方式。简单的状况的确如此,字符集等于编码,编码等于字符集。 可是,一般把咱们搞晕的,正是一个例外,Unicode。Unicode字符集自己定义的编码方案一般称为UCS-2,或者一个更通用的名字, UTF-16。然而,因为UTF-16不能和现行的基于ascii的编码方案兼容,比较重点的问题在于0x0,在基于ascii的编码方案中,一个8位的 0x0老是表示一个字符串的结束的,而UTF-16则否则,它的一个字符,彻底有可能在高8位或者低8位上等于0x0,这会致使不少应用程序错误,尤为是在网络传输协议当中可能致使大量的字符串错误截断。因而,有了UTF-8,UTF-8提供了一个跟ascii兼容的unicode字符集编码方案。网络上常见的说法说UTF-8是1到3位变长编码,这是错误的,UTF-8是1到6位变长编码,3位的说法来源于大多数经常使用汉字被包括在3位编码的范畴之内,而另外,从现行的Unicode规范来说,UTF-8其实是1到4位的编码,由于再加上两位编码所扩展的范围如今Unicode尚未定义任何字符。 UTF-8的编码方案首先保证跟127个标准ascii字符兼容,也就是说,在UTF-8方案下,Unicode的0x000000–0x00007F范围的字符被表达为0x0-0x7F的一个字节的二进制编码。其次,UTF-8保证,全部0x7F以上的字符,在被转译成多字节字符时,每一个字节的最高位必定为1,这实际上也是大多数MBCS方案的基本原则,不然应用程序无法识别多字节字符的字节组合方式或者出现错误的0x0。问题在于,通常的DBCS双字节方案能够简单的根据高位是否为1而断定单字节仍是双字节,而UTF-8是变长的,应用程序须要知道如何组合连续的字节数据,按照UTF-8的规定,除了最高的一个字节外,其他的全部字节均以10开头,而最高字节的开头,110表示连续2位,1110表示连续3位,11110表示连续4位。(一个具体字符的UTF-8编码值根据一个简单的对应算法从UTF-16获得,这里就不详细讲述,请自行google)。所以,咱们必须明确一个概念,UTF-8是 unicode字符集的一个编码方案,当咱们在说到UTF-8字符和Unicode字符的时候,在某些状况下,它们在逻辑上是等价的,可是,他们并非同一个东西,由于Unicode字符在二进制上还有一个选择就是原生的UTF-16编码。 总结一下,Unicode字符集规定的标准编码方案是UCS-2(UTF-16),用两个字节表示一个Unicode字符,而事实上,UCS-4 (UTF-32)也已经被提出了,用4个字节表示一个Unicode字符,而后,一个经常使用的Unicode编码方案—UTF-8,它用1到4(6)位的变长字节来表示一个Unicode字符,并能够从一个简单的转换算法从UTF-16直接获得。这三个编码方案(Encoding)都对应于Unicode字符集(Charset)。 而后,须要解释一下Codepage-代码页,codepage其实是一张表,一般的codepage是一个从unicode到其余mbcs的转换索引表,好比windows上经常使用的MS936代码页,实际上就是GB2312到unicode的转换表,咱们知道,windows是彻底基于 unicode的,MS的应用程序也大可能是基于unicode开发的,他们对GB2312的支持,正是来源于codpage932,经过cp932的转换,应用程序能够在unicode和gb2312之间来回转换。须要多一句嘴的是关于日文编码,IBM和微软都提供了几个工业上经常使用的日文编码的代码页,好比对于shift-jis,IBM的代码页是CCSID943,这也是java在转换时使用的代码页,而MS的代码页是MS936,他们二者都是针对 shift-jis的代码页,算是两个并行的工业标准,在某些字符上转换结果并不一致,这可能会致使应用程序错误,好比我遇到的典型问题是经过java程序将shift-jis数据转换为unicode后传输给VC编写的程序再转换为shift-jis,因为在两次转换中使用了不兼容的代码页,致使数据错误。这并无什么特别的解决办法,只能是查找特殊字符列表做特殊处理。 另一个问题,就是所谓的基于unicode的应用程序,在应用程序内部字符串究竟以什么形式表达,通常来讲,是以UCS-2也就是UTF-16 的二进制形式来表达的,UTF-8通常只是做为数据传输格式和文档保存格式。具体一点,对于java代码,javac编译程序在你没有指定源文件编码的状况下,老是将其认为是本地缺省编码,好比在简体中文windows上会被认识为GB2312,而在日文windows上会被识别为shift-jis,而后实际上,在编译的时候,gb或者jis字符都会被转换成对应的UCS-2二进制值。而对于C++程序,当你简单的用 ”中” 这样的引号引用的形式的时候,编译器会简单的将其识别为本地编码而且在编译后的二进制代码中被表达为本地编码的二进制值(我不知道c++编译器可否指定源文件编码。。。我不太熟悉c++),可是,若是你用 L”中” 这样的标准c++的unicode字符定义方式来定义字符时,将会发生和javac编译程序同样的事情,编译程序会主动的将字符正确的以本地编码识别并转换成UCS-2值保存为编译后的二进制代码。C++程序中,若是以L宏定义字符串,能够在程序中直接获得Unicode值,即UTF-16编码值,但在 java中,实际上咱们并不能直接获得字符串的二进制值,不过能够经过String的getbytes方法指定UTF-16编码获得。至于各类编码之间的转换,这里就不赘述了。 最后,解释一下关于font的问题,其实,不少时候咱们遇到的乱码并无出现编码转换错误,只是因为应用程序指定的字体没有包含对应的字符图像而已,这种状况,一般咱们能够看到有部分字符是能够正常显示的。Font文件实际上也是一个索引文件,一个encoding索引加上位图。如今的字体文件一般包含两个编码索引,一个unicode,一个该字体对应语言的经常使用编码,应用程序在显示字符的时候,经过查找对应的索引而获得字符的位图。
相关文章
相关标签/搜索