这里新的话题就是字符编码以及国际化的问题。在写完这个话题之后,我们就将开始"Win32 Application"的旅程。
既然你在看这篇文章,那我就假定你是一个开发者,并且对于ANSI,ASCII,Unicode,UTF8这些名词都有所了解,至少是听说过这些概念。因为这个例子中,我们就会使用到这些概念。如果你对于这些概念不熟悉,那请先从我的“参考”链接中找到对应的条目进行研究,然后再开始做这个例子。
OK,那我们就可以开始了。首先,打开你的Notepad,中文系统中叫做“记事本”。下面是一个空的打开的记事本:
我们来输入一些文字。
我们现在输入了一行中文,一行英文,并且带了一些标点符号,同时有一个换行符。
现在我们需要用一些其他的辅助工具,我这里用的是Notepad++以及它的一个叫HexEditor的插件,不喜欢使用的同学们可以用其他类似的工具代替,如WinHex或HexEdit等十六进制编辑器。用工具将这个txt文件打开,来看看这27个byte是怎么组成的。
打开文件后,点击工具栏上的“H”图标,我们来看看十六进制。
其实这里的对应是有些小问题的,对于中文的部分,dump出来的映射关系在移动光标的时候有些不准确,但是这个并不是影响很大,我们可以忽略。我们可以挑选其中几个来看看,这里的“你”对应的十六进制为“c4 e3”,也就是0xC4E3;"l"对应的十六进制为"6c",即0x6C。我们在这里看到的映射关系,就叫做字符编码(character encoding),而所有字符编码的集合,我们叫做字符集(character set--charset)。
我们在这里看到的是ANSI编码的,可以回过来看一下“保存”的那个截图,最下方的"encoding"选择的是"ANSI"。我们在保存文件的时候,还可以有其他选择。用saveas来另存一下。
可以看到,除了ANSI选项外,我们还有3个选项。
我们也将其用Notepad++打开,查看其十六进制。
当你有耐心看到这里,并且明白了我上面所写的内容的话,背景介绍完毕。下面就开始真正介绍“字符编码”了。
首先,上面我们所做的都是针对简体中文环境下的字符编码,至于其他编码,我们还没有涉及到,之后会谈到。对于“你”这个字符,在ANSI中,为0xC4E3;在Unicode中,为0x4F60。这是由不同的标准所决定的,决定前面的标准为中国国家标准,包括一系列一脉相承的标准,从GB2312到GBK到GB18030。决定后面的为The Unicode Standard。为什么会出现这么多标准,这是由历史原因以及当时的机器性能决定的。
历史
刚刚前面一直提到ANSI,其实并不是那么准确的,其中我们要涉及到codepage的概念,这里我们的codepage为936,也就是简体中文,在这个环境下,我们的ANSI编码表示才是中国国家标准的那套。ANSI真正的含义是“美国国家标准协会”(American National Standards Institute)。就是这个协会,定义了字符编码的“鼻祖”--ASCII码。现在的字符编码,大多是基于ASCII码扩展而来的。
ASCII(American Standard Code for Information Interchange, 美国信息交换标准代码)是一个7位(7-bits)码,包含了128个字符的定义(128=2^7),其中有33个非打印控制字符,以及95个可打印字符(包括空格),主要是用来显示英文字母的,其对应的ISO标准为ISO646。为了避免概念混淆,IANA(Internet Assigned Numbers Authority,互联网号码分配局)使用US-ASCII来称呼该字符集。至于为什么定义7位而不是一下子8位,当时是个“锱铢必较”的时代,内存太紧俏太贵了,能省一点是一点哈,够用就行。
尽管能表示英文字母,但是还是有很多字符还是无法表示,比如德文中的öäüß等,于是不够用了,然后就出现了扩展ASCII码(Extended ASCII),也就是将ASCII码从7位扩展成了8位,这样一共就有了256个字符。EASCII码比ASCII码扩充出来的符号包括表格符号、计算符号、希腊字母和特殊的拉丁符号。这里,就开始有了区分,对应的标准并不是一个,而是一系列的8位字符集标准,在ISO标准中叫做ISO 8859,全称为ISO/IEC 8859,现在定义了15个字符集(这里有16个,应该是希伯来语一个是视觉顺序,一个是逻辑顺序,为1个,猜想,未验证)。
上面的这些字符问题,基本解决了,下面就是比较麻烦的了。上面的字符,用1个byte都能够表示完整了,叫做SBCS(Single Byte Character Set)。但是咱们是象形文字啊,几千个字符,这小小256个地方怎么够用呢?于是没办法,扩1个byte吧,于是叫DBCS(Double Byte Character Set)。对于CJK语言(以中文、日文、韩文为主的东亚语言),基本上使用2个byte表示一个字符的编码方式来进行表示。具体了解的有日文、简体中文、韩文、繁体中文(至于泰文并不是很清楚,据有些同学说是3字节编码?资料没有找到很确切的,希望了解的同学指导一下)。
我们最熟悉的当然是简体中文了,所以就看这个,其余除了以前玩大宇游戏的时候,知道“大五码”(Big 5),用过南极星,就了解不深了。这里就不做介绍了。
GB 2312标准共收录6763个汉字,其中一级汉字3755个,二级汉字3008个;同时收录了包括拉丁字母、希腊字母、日文平假名及片假名字母、俄语西里尔字母在内的682个字符。GB 2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。
尽管覆盖了99.75%,但是还是有没覆盖的,所以之后又出现了GBK和GB-18030。这里对于编程人员的建议就是,如果需要更全的字符覆盖,就使用GB-18030,如果是嵌入式系统,需要在更小的内存中实现较多的功能,使用GB-2312即可,甚至在某些场合,可以使用其子集(一般嵌入式系统需要显示的字符是可以统计出来的,有些字符并不需要)。
这样,对于非Unicode部分的字符集,基本上要了解的都介绍了。不过,如何使用呢?我Latin-1的和GB 2312的,其同一个十六进制,对应的字符不一样、同样用“你”的编码来说,对应为0xC4E3,对应到Latin-1中,就是两个字符,Äã,两个是不能共存的。
在这种情况下,有一个新的概念出现了:
为了使用不同的字符集,我们使用不同的codepage。不同的codepage对应不同的字符集。对于简体中文,其codepage为936;日文的codepage为932;韩文的codepage为949;繁体中文的codepage为950。我们可以参考Windows下面的Region and Language Option设置,对于“非Unicode”语言设置,选择的就是特定的codepage。