细说字符集(CharSet)和字符编码(Encoding)
本文将阐述字符集(CharSet)、字符编码(Encoding)之间的关系,以及浅谈集中常用的中文字符集和编码
概述: 中文的乱码现象,以及繁简中文的乱码现象在以中文主导的地区时有发生,而解决乱码的根本,就必须要明白电脑是 到底是如何存放和编排我们日常所见的字符,本文将深入探讨,并对有关的名词给予深入的解释,希望之后再遇到有关的编码的问题, 能够游刃有余。
1. 什么是字符集(CharSet)?
charset is the set of characters you can use
在英文资料中,与字符集(CharSet)可以同意的词汇有 character set, character map, codeset or code page
简单讲,字符集就是某一类字符的集合。比如说常用的英文字母和符号都包含在ASCII这个字符集中。 再例如,我们看到的简体和繁体汉字,其实都有各自的字符集,简体汉字的常用字符集有以下几种,GB2312/GB 13000/GBK/GB18030。 同理,繁体字字符集Big5包含了常用的繁体字。概括的说,字符集规定了某类字符对应的二进制数值存放方式(编码),通过一个二进制数值 在某种字符集中寻找出对应代表的字符就是解码的过程。
那么问题就来了,为什么我们会看到业界有如此多的字符集,诸如UTF-8/UTF-16/Unicode等各式各样的字符集呢?很明显,字符集的产生是随
着计算机不断发展壮大带来的问题,首先当时字符集标准的制定者没有意识到要建立一种标准通用的准则,特别是当初计算机只在英文和欧洲语系
的国家流行(相对来说,英文和拉丁字母数量少,编码容易)。然而他们没有意识到,随着科技发展,电脑已经深入到各个国家和民族当中,自然
每个民族都希望自己的语言能被电脑识别,因为各个国家语言的字符集都相继推出,这也导致字符集不断壮大。既然如此,可否制定一个通用编码
原则,让每个后来创建的字符集按照制定的方式来编码,这样不就解决了不统一的问题了吗?事实上,
字符集 | (“欢”)编码值Hex Value |
---|---|
GBK | 0xBB66 |
Unicode | 0x6B22 |
2. 什么是字符编码(Encoding)?
encoding is the way these characters are stored into memory
读到这里,大家应该有个印象,字符集是某一种字符的集合,要找到某个字符,那首先就应该找到改字符所在的字符集,那么下一步就应该是如何从 字符集找出对应的字符了。
事实上,要从一个字符集正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码字符集(coded character set)、
字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,
字库表决定了整个字符集能够展现表示的所有字符的范围。编码字符集(coded character set),即用一个编码值
不过问题就来,从上文可以看到,其实只需要
3. UTF-8和Unicode的关系?
看完上面两个概念解释,那么解释UTF-8和Unicode的关系就比较简单了。Unicode就是上文中提到的编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。详见:Unicode on Wikipedia。Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库。
4.UTF8编码
上一节已经介绍了有关utf-8的编码知识,下面具体解释下,到底什么UTF-8编码。
UTF-8编码为变长编码。最小编码单位(code unit)为一个字节。一个字节的前1-3个bit为描述性部分,后面为实际序号部分。
举个例子,前面我们提到了“欢”字的Unicode是0x6B22,按照以上的规则,可以通过其Unicode得到相应的UTF-8 encoding。
“欢” | Binary Stream |
---|---|
Unicode | 0110 1010 0010 0010 |
UTF-8 | 1110 0110 1010 1000 1010 0010 |
5.乱码原由
在实际编程中,经常会出现乱码的现象。当我们理清了字符集、字符编码这些概念后,便知道其根本原因就是,我们错用某种字符编码去decode另外一种字符编码,最常见的错误就是,把一个UTF-8编码后的字符,用GBK去解码,
这样,常常就会出现一些无法理解的符号或者其他离奇的汉字,以欢字为例,其utf-8的编码的二进制流是
Reference: