关于Unicode,字符集,字符编码,每个程序员都应该知道的事
基本概念
字符[character]
字符代表了字母表中的字符,标点符号和其他的一些符号。在计算机中,文本是由字符组成的。
字符集合[character set]
由一套用于特定用途的字符组成,例如支持西欧语言的字符集合,支持中文的字符集合。字符集合只定义了符号和他们的语意,其实跟计算机没有直接关系。
现实生活中,不同的语系有自己的字符集合,例如藏文有自己的字符集合,汉文有自己的字符集合。到计算机的世界中,也有各种字符集合,例如ASCII字符集合,GB2312字符集合,GBK字符集合。还有一个其他字符集合的超集--Unicode字符集定义了几乎绝大部分现存语言需要的字符,是一种通用的字符集,来支持多语言环境(可以同时处理多种语言混合的情况)。各个国家和地区在制定编码标准的时候,“字符集合”和“字符编码”一般都是同时制定的。所以像ASCII字符集合一样,它也同时代表了一种字符的编码。
字符编码[character encoding]
是一套规则,定义了在计算机内存中如何表示字符,是字符集中的每个字符与计算机内存中字节之间的转换关系,也可以认为是把字符数字化,规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储。例如ASCII编码[你没看错,它既是一种字符集合,也是一种字符编码],定义了英文字母和符号在计算机中的表示方式,是用一个字节来表示。Unicode字符集合,有好几种字符编码方式,例如变长度编码的UTF8,UTF16等。中文字符集也有很多字符编码,例如上文提到的GB2312编码,GBK编码等。
知乎上的这篇介绍字符编码,字体,iconv的文章很赞,内容浅显易懂。还有一篇很有名的有关Unicode和字符集的文章可以看看:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!),网上有中文版。
UCS和ISO 10646标准
ISO 10646标准定义了通用字符集UCS[Universal Character Set],是其他所有字符集合的超集。它保证了和其他字符集合之间可以来回转换,不会丢失信息。
UCS不仅给每个字符做了编码,而且还定义了一个官方的名称。用来表示一个UCS或者Unicode的十六进制数字通常是用"U+"来作为前缀的,例如用"U+0041"来表示拉丁文中的大写字母A。
UCS[Universial Character Set]和Unicode的关系
简单粗暴的总结一下,就是两拨人搞的同一套标准。具体经过如下:
在1980年代后期,有独立的两拨人想创建一个通用的字符集合。一个是国际化标准组织ISO[Internaltional Organization for Standardization],另外一个是最初成员大部分是美国多语言软件服务提供商的财团发起的Unicode项目。幸运的是在1991年左右,两个项目的成员都意识到世界不需要两个统一的字符集。于是他们一起合作制定了一个字符表。虽然两个项目至今仍然存在并独立发布各自的标准,但是Unicode财团和国际化标准组织都已经同意会让Unicode和ISO 10646标准互相兼容并会在未来紧密协作。具体两者之间的区别,见这里
什么是UTF8
Unicode/UCS只是字符集合,虽然为每个字符分配了一个唯一的整数值,但具体怎么用字节来表示每个字符,是由字符编码决定的。Unicode的字符编码方式有UTF-8, UTF-16, UTF-32。由于UTF-16和UTF-32编码中包含"0",或者"/"这样对于文件名和其他C语言库函数来说具有特殊意义的字符,所以不适合在Unix下用来做文件名称,文本文件和环境变量的Unicode编码。UTF-8没有这样的问题,它有很多优点:可以向前兼容ASCII码,是变长的编码,由于编码没有状态,所以很容易重新同步,在传输过程中丢失了一些字节后,具有鲁棒性。
POSIX语系[locale]机制
语系[locale]就是软件运行时的语言环境,它是语言和文化规则的一个集合,包含字符编码,日期/时间的表示方式,字符排序的规则等。语系的名称通常是由ISO 639-1规定的语言[language]和ISO 3166-1规定的国家代码[country code]以及额外的字符编码名称[character encoding]共同组成,例如zh_TW.UTF-8语系,zh代表语言是汉语,TW是台湾地区,UTF-8是字符编码。而zh_CN.GBK中,CN是指中国大陆地区,采用GBK编码。
Linux下语系由几个类别的环境变量组成,指定了在软件中跟语言惯例相关的行为信息。例如LC_CTYPE决定字符编码方式,LC_COLLATE决定字符排序的规则。LANG环境变量用来设置所有类别的默认语系,但是LC_*这些变量能够覆盖每个单独的类别。