显示标签为“计算机技术”的博文。显示所有博文
显示标签为“计算机技术”的博文。显示所有博文

2009年2月28日星期六

Unicode, A programmer should know

首先说说这个标题,因为我最近非常迷星战,所以顺带也喜欢上了Yoda大师说话的腔调,以后可能会用的更多,情别见怪(反正也没人看)。

“曹操”为什么会变成“变巨”一文中,我提到了Unicode是多语言共存的解决方案,本文将详细介绍Unicode,以及为什么解决了各种令人头疼的编码问题。

那unicode解决了哪些问题呢?其实最主要的是这几个问题:

  1. 人们希望有一个单一的字符集,能包含这个星球上所有的字符
  2. 每个字符都有一个独立的编号,不会出现一个编号对应不同字符的事情
  3. 可以根据需要变换不同的编码方式,但是不会影响字符编号
那么看看unicode是怎么解决这些问题的呢?

Unicode 是一个国际标准,它主要包含了:
  • 超大的字符集,可以有1,000,000个字符,code space为[0x0-0x10FFFF]
  • 每个字符的code point编码方法
  • 一个标准的字符集
  • 一组字符属性的枚举值
  • 提供字符集的多种编码
有很多人把unicode 与utf8,utf16这些编码混为一谈,看完本文后,应该不会再存在这样的混淆了。

Unicode有其标准的书写格式。要表示一个字符的Unicode码,可以这样写:
U+0041 
这就是大写字母A的Unicode码,U+表示这是Unicode码,后面的十六进制数字是这个字符的unicode code point。比如hello的code point就是U+0048 U+0065 U+006C U+006C U+006F。可以看到,这些码值去掉前面的00,就跟ASCII码一样了,是的,unicode最大限度跟ASCII保持兼容。

Unicode的字符集可以说包括了这个星球上所有的字符。包括一些我们可能永远也不会遇到的字符。不过Unicode标准把一些最常用的字符放在0x0000-0xFFFF这个区间中,这样有些系统实现的时候就不需要用那么多空间来存放不常用的字符了。这个区间被称为BMP(Basic Multilingual Plane)。Unicode一共有17个Plane,有6个已经被占用,剩下的都是空的。如下表所示:

Plane RangeDescriptionAbbreviation
0 0000-FFFFBasic Multilingual PlaneBMP
1 10000-1FFFFSupplementary Multilingual PlaneSMP
2 20000-2FFFFSupplementary Ideographic PlaneSIP
3-13 30000-DFFFFcurrently unassigned
14 E0000-EFFFFSupplementary Special-purpose PlaneSSP
15 E0000-EFFFFSupplementary Private Use Area-A 
16 E0000-EFFFFSupplementary Private Use Area-B 

在BMP中的任何一个code point都用4位16进制数来表示。其他的plane中的code point用5-6位。

Unicode的编码问题是我们最关心的。Unicode允许使用不同的编码方式,也就是你平时看到的utf8, utf16之类的名字。他们的特点在于编码出来的值各不相同,但是解码之后,都对应到一个唯一的unicode code point。这样保证了unicode编码之间可以无损(在BMP中)转换以及映射(mapping)的唯一性。Unicode中把一个值的code point及其使用某种编码得到的码值称为一个映射(mapping)。

在unicode发展过程中,出现过多种编码。我这里就介绍几种主要的编码,在此过程中出现过两个组织,各自发展出一套映射方法,称为Unicode Transformation Format(UTF)和 Universal Character Set(UCS)。 后来两个组织合并在一起,UTF和UCS也随之合并了。简单的说它们之间的对应关系是UTF后面跟的是一个编码的位数,UCS后面跟的数字是编码的字节数(以八位作为一个字节),比如UTF-16和UCS2几乎是同一个东西。但实际上UCS2只实现了BMP内的字符编码,而UTF16则实现了所有unicode编码。但为了简单期间,我们在这里认为它们是一个东西。

UTF-16/UCS2
最直观的编码方式就是一一映射。一个unicode码对应一个UTF-16编码。比如上面所说的hello,其编码为00 48 00 65 00 6C 00 6C 00 6F。但是问题马上来了,在大端法(big endian)和小端法(little-endian)的机器上编码得到的串的顺序不一样。在大端法的机器上,同样hello经过编码得到的是48 00 65 00 6C 00 6C 00 6F 00。而48 00也是一个合法的unicode code point,因此把在大端法机器上保存的文件拿到小端法机器上读就会解析成完全不同的东西。人们于是想到用最前面的两个字节来标明字节顺序。这两个字同样是unicode码,U+FEFF,一般被称为BOM(Byte Order Mark)。FE FF表明大端法,FF FE表明小端法。

UTF-16使用2个字节来进行编码,因此只能编码到BMP的code point。对于其他的plane,UTF-16采用一种额外的编码方式,达到3,4字节的编码。但是一般情况下,UTF16指的就是2字节的编码。这样的编码非常方便,所有的字符都占用一个unsigned short,对于传统的c字符串函数就非常方便。

在windows上,为了方便utf16被直接称为unicode编码,与ANSI对应。你在使用notepade时可以保存成unicode,指的便是utf16。

下图显示了在linux上使用utf16编码



比较下在windows下使用utf16(unicode)编码,注意到BOM了吗?




UTF-8
UTF-8可以说是用得最广泛的编码方式了,很多Linux的发布版都使用UTF-8作为其系统编码。UTF-8的产生原因可能是由于有人觉得UTF-16太占用空间了。在美国英语系统下,每一个字符都有一个00,字符串大小凭空增加了一倍。于是人们研究出UTF-8这个可以兼容ASCII的变长编码方式。UTF8编码出来的字符占1-4字节。

具体占位如下图所示:


对于在U+0000到U+007F区间(是不是很熟,对了,就是ASCII码的区间)内字符,使用1个字节来编码,因此完全兼容ASCII码,而且省空间。

[U+0080, U+07FF] 区间内的字符,基本上是欧洲各国字符集,使用2个字节来编码。
图中的yyy是code point中的高位字节,由于最多到7,因此只要3个bit就可以编码。
图中的xxxxxxxx是code point中的低位字节,从00到FF,需要用的所有8个bit,在编码时,把低位的6个bit与10结合作为一个字节,剩下的2个bit与yyy,110结合作为一个字节。

[U+0800, U+FFFF] 区间内的字符,包括中文,日文,韩文等都使用3个byte来编码。详细的编码规则在图中已经解释的很清楚了,我这里不再重复。

下图显示了在linux使用utf8编码,于utf16的截图相比,utf8对曹操这两个中文各用了3个byte进行编码。



比较下在windows上使用utf8编码,首先是字节顺序不同。然后你还可以看到utf8的BOM,0xEF 0xBB 0xBF。这BOM不仅和系统,还和使用的软件有关。notepad无论什么编码都会加上BOM。



UTF32/UCS4
这是最浪费空间的一种编码方式,它也是一一映射,但是UTF32映射了所有的unicode code point。对于每一个code point,UTF32如其名字所示,使用32bit也就是4个字节来进行编码。比如A=00 00 00 41。

很多程序使用utf32作为内部编码,在保存的时候它可以无损的转换成其他编码。而且因为现在的硬件总线的关系,这种编码的寻址和读写更快。比如Apache的Xerce2 就是这么做得。



还有其他很多编码,比如国标的GB18030。只要符合unicode标准,你也可以创造自己的编码。


讲了这么多,最初的问题也算回答得差不多了。Jeffrey Richter[1], Joey Spolsky[2], Charles Petzold[3]等人都在各自的著作中强调unicode对现代编程的重要性。虽然我人微言轻,但是我还是想附和一句:unicode以及编码的知识应该是每一个专业的程序员需要了解的知识。现在,停止ANSI程序,开始用unicode编写你的正式程序吧。




注1:《Programming Applications for Microsoft Windows》, chapter 2, Jeffrey Richter
注2:《Joel on software》, Charpter 4, Joel Spolsky
注3:《Programming windows》,chapter 2, Charles Petzold

2009年2月21日星期六

“曹操”为什么会变成“变巨”?


以前在PC上玩过三国志的人大多数都会记得一个奇怪的词——“变巨”。但大家都知道,那是曹操,因为头像放在那,一看就知道是曹操,一张枭雄的脸。可是为什么会显示成“变巨”呢?有些人会说,编码问题呗。是的,那到底是怎么回事儿呢?

这个问题的根本原因可以说是编码和解码方式不匹配

要解释这个问题,首先要解释下Code Page的概念。在Windows下,打开控制面板->区域和语言选项->高级,里面就有代码页转换表。我们在里面会看到类似936  (ANSI/OEM - 简体中文 GBK) 这样的选项。这就是一个Code Page(代码页)。

Code Page最早始于IBM,当时个人PC上只有ASCII码,用0x00-0x7F这128个code point(代码点)来编码控制字符,数字,大小写字母,特殊字符和打印符号等。但是很快ASCII码就无法适应需求了,更多的西欧字符要求被加入码表。于是出现了EBCDIC codepages。这些Code Pages扩充了ASCII码,成为256位的一个码表。前面0x00-0x7F与ASCII码保持一致,后面的128根据不同的语言定义不同的code page。微软一开始借用了这些CODE PAGE,之后用自己的ANSI(或者说ISO 8859-1)的code page作为补充,成为现在我们在Windows操作系统上的CodePage。

在Windows操作系统中,对CJK(Chinese,Japanese,Korean) 也用Code Page进行处理。但是中文等语言的字符实在太多,不可能用256位的code page来表示,那怎么办呢?一个直观的想法是用双字节来编码一个字符,理论上就可以安置65536个字符。也可以用多字节来表示,单字节部分可以兼容ASCII码,双字节部分编码CJK字符。在code page设计时是怎么考虑的我不知道,但最后还是采用了后一种方式。

看下图:


这是一张Windows Codepage 936(以下简称CP936)的示意图。前面0x00-0x7F和ASCII码一致,和Windows上其他的codepage保持一致。后面128个字节被称为lead byte,用来和另一个byte组合成一个CJK字符的编码。每个lead byte又对应一张子表,比如0x81这个lead byte对应的子表如下图所示:


于是汉字“丢”的GBK码就是0x8147。但是子表并不一定都是256个字符。理论上GBK码按照这种方式可以编码128*256个=32768个字符。但实际上中文字符要多的多。因此出现了其他更好的编码,这里先按下不说。Windows的设计的这个字符集被称为MBCS(Multi Byte Character Set)。

知道了codepage的概念,我们就可以解释“曹操”-“变巨”的问题了。为什么我开头说“编码和解码方式不匹配”呢?想想看,曹操是存放在什么地方的?用什么编码存放的?

对了,曹操两个字是存放在资源文件里面的。而我们玩的三国志是第三波汉化的繁体中文版,也就是说,曹操两个字是以BIG5码(CP950)进行编码的。从以下的CP950_B1可以看到,“曹”字的编码是:B1E4。而我们是在简体中文的Windows上玩这个游戏的,对于磁盘上存放的B1E4,我们用CP936 GBK码来解码的。从下面的CP936_B1可以看到B1E4正好就是“变”字。



同理可以知道操对应的是巨,繁体字赵云对应的简体字是化冻。

事实上,这小小的一个问题,牵涉到Locale,字符集,codepage,编码等各种问题。
而CodePage在使用过程中也暴露出很多问题;最主要的就是一个代码点(code point)在不同的codepage中代表不同的字符,变成了一对多的关系,导致在一个程序中没法使用多语言。不同的厂商在设计code page时缺少文档,不利于交流等。

解决这些问题的,就是Unicode。我会在最近的blog中详细介绍Unicode。因为Unicode是每个程序员需要了解的概念。

最后,我总结下Code Page的概念:
  • Code Page只在Windows和IBM的mainframe上有,Linux/Unix等操作系统并没有这个概念。
  • Code Page是为了解决多语言及本地化的问题而产生的。
  • 使用Code Page,无法在一个程序中支持多语言。
  • 在Windows中,一旦换了Code Page,我们需要重启。
  • Code Page提供了字符集和编码/解码方式。

更新于2009.2.28: 关于unicode的介绍已经写好了--Unicode, a programmer should know

2008年10月8日星期三

My VS2005 Color Scheme

我今天花了点时间改了改VS2005的配色和字体方案,把原来整体白色的效果改成了现在的灰暗的效果。主要原因是保护眼睛。白色虽然明快,对比度高,但是会反射所有的光线,而黑色则相反,可以保护程序员的视力,至少不会看着很吃力。不相信可以自己试一下,把液晶显示器的亮度调高,盯着看一段时间,然后再调暗,眼睛是不是轻松很多。

然后字体从原来的Courier New改成了现在Monaco,这个字体非常好看。也是网上很多人推荐的编程用字体。效果图如下:


我个人不太喜欢花里胡哨的配色,所以颜色看起来不是很鲜艳。这样的好处就是让眼睛少受刺激。颜色太多,眼睛受到的刺激也会增加,长时间盯着看反而会吃力。

我的配色方案如下:
Font: Monaco (size 10)
Background : RGB(25, 25, 25) Not completely black

Plain Text : White
Line Number: RGB(43, 145,175 )
Comment : RGB(135,206,235 ) bold
Identifier: RGB(207, 207, 207 ) bold
Keyword: RGB( 68, 68, 255 ) bold
Number: RGB( 0, 128, 128 ) bold
Preprocessor Keyword: RGB ( 175, 96, 255)
String: RGB(252, 71, 39) bold



在《Monospace/Fixed Width Programmer's Fonts》一文中,作者列出了他认为写程序用的字体,应该具备哪些条件:

  • Crisp clear characters.
  • Extended characterset.
  • Good use of whitespace.
  • 'l', '1' and 'i' are easily distinguished
  • '0', 'o' and 'O' are easily distinguished
  • forward quotes from back quotes are easily distinguished -prefer mirrored appearance
  • Clear punctuation characters, especially braces, parenthesis and brackets

简单的说,首先要清晰,然后才是美观。总的来说,我觉得还是有道理的。我以前一直使用Courier New就是因为这个字体很清晰,在VS2005中如果更改字体,那些加粗的都是等宽字体,也是写代码首选的字体。网上讨论的比较多的是三款字体,分别是Bitstream,Monaco,Consolas,分别是Linux,Mac,Windows三个平台上的代表字体。我选择了Monaco,这块字体乍看之下不怎么样,但是仔细看看还是很有味道的。有兴趣的朋友可以试试。

另外,这几个配色方案也是我比较推荐的:
Dark Visual Studio
Scott Hanselman's color scheme
Slimcode
Jeff Atwood

相关文章:
Programmer 最佳用字型 Monaco font
Best font for programming is...?

2008年4月25日星期五

Ubuntu 8.04 LTS Release

凌晨3点,我还在公司里面加班。我刚刚完成了Release,随手就打开浏览器输入www.ubuntu.com, 因为我知道,今天是Ubuntu 8.04 LTS 正式Release的日子。一看果然Ubuntu的首页不同了,大幅的广告显得喜气洋洋。

Ubuntu 8.04 新增加了许多非常酷,非常实用的功能,Ubuntu桌面环境已经非常实用,这次对硬件支持也更加完善,而且新加入的PulseAudio也提升了其多媒体性能。Ubuntu 8.04集成了现在市面上最新的软件包,比如:Firefox 3,Compiz Fusion 0.7.4,GNOME 2.22,甚至还可以依靠Likewise与windows 的活动目录无缝链接(可以使用Windows域的打印机,可以通过域用户访问域资源)。最后,还有几近完美的升级程序,可以完美的从7.10升级到8.04。由于使用了新的引擎,Nautilus 性能提升堪称恐怖。

还在等什么呢?快去下载吧!
http://www.ubuntu.com

2008年3月12日星期三

开源和免费

今天上网的时候在PCHOME上看到一篇文章《够用就好 常用共享软件的免费替代品》。里面介绍了几个常用软件的开源或免费替代品。在我们这个不注重版权的国家里能有人提倡这个,看来人们也开始关注这方面了。事实上,在很多大公司里面都很注意这方面的问题,有些公司很严格的完全杜绝盗版,比如我一个朋友所在公司“中芯国际”。他们很早就已经强制把ultraedit,acdsee等软件请出了硬盘。一开始,人们不习惯,但是经过一段时间的适应,人们也慢慢有了版权意识,就算在家里也只用开源或者免费软件了。这方面,台湾人做的的确不错。

我自己用的大多数也是开源和免费软件。我这里也介绍一些我常用的软件。作为PCHOME那篇文章的补充。

Office软件:
SUN OPENOFFICE 2.3非常不错,完全兼容MS Office。不是我不支持国产软件,但是我一直不怎么喜欢WPS。

压缩解压缩:
7zip,绝对是7zip。其实winrar也可以不买一直用,只不过如果要浏览内容的话会出现一个提示窗口。7zip的速度完全没有问题,我解压缩一个1g的rar文件,用winrar是4分13秒,用7zip是4分16秒,效率上差不多。另外压缩比例7zip要比rar高一些。LZMA算法果然强悍!

图像浏览
IrfanView不错,界面稍微丑了点,Picasa也很不错。两个正好互补用来看单个图片和批量图片。

文本编辑
文本编辑对于我们程序员来说是很重要的。因此我有好几个编辑器,一个是基于SciTE的Notepad++,一个是vim7。一般情况下Notepad++已经可以胜任大多数情况,界面也非常友好。vim7可以提供一个很强大的编程环境,vim+ctags以后就能通过函数名找到函数声明,对读代码很有用处。vim的!%xxd命令可以用来查看二进制内容,这使得我最后一个留恋Ultraedit的理由也没有了。vim另外一点就是所有操作几乎都可以在主键盘上完成,对于使用笔记本的人来说很方便。emacs我也用过一段时间,但是emacs时间比较复杂,所以我放弃了。

图像处理
Paint.net需要.net支持,所以我不太感冒。我使用的是Unix下大名鼎鼎的Gimp。一开始可能用不管,但是时间长了就知道他的强大之处了。我个人认为比Photoshop有一段差距的,但是一般处理图片绝对能胜任。

PDF
阅读PDF当然是用Foxit Reader。这么快的pdf阅读器,谁不用谁是傻子!
生成PDF,有两个工具。一个是我常用的open office 2.3,直接保存成pdf。另外一个是Letex,这个我在linux下用,据说也有windows版,生成的PDF绝对漂亮!

听音乐
千千静听和foobar这两个我都用过,最后还是foobar占据了我的硬盘。无他,就是喜欢简单的工具。如果想听APE需要下载一个插件。

FTP
FileZilla,我用下来感觉很稳定,很方便,很强大。大概带Zilla的东西都不错。不知道以后会不会有Zilla Fan这一说!

源代码管理
公司用的是又贵又不好用的Clearcase,现在在Clearcase下面我连Debug都不行,只能靠打trace或者用Dump Stack来分析问题。因此我喜欢小巧的SVN,配上windows上最好的客户端TortoiseSVN,已经能完全满足一个大型公司的要求了,更别说我自己个人开发了。

播放器
还用说么?Windows Media Classic 6.4.9.1。稳定,CPU占用率小,启动快,自动加载字幕,对一般看看片子够了。另外国产的酷热影音也不错,速度很快,插件管够!

安全
安全涉及到杀毒软件和防火墙。我用的是Avast! Home版。这个捷克的软件我很喜欢。CPU占用率中等,每天自动更新。实在不放心再装个360安全卫士。Windows这东西防是防不住的,只能自己注意不要上乱七八糟的网站。浏览器用FF可以防止一些ActiveX控件。

基本上一般日常使用的软件都在这里了。详细以后会有越来越多的付费软件被开源或者免费软件所替代。

2008年3月11日星期二

搞定无线路由

昨天在淘宝上买的NETGEAR WGR614终于到了。拿到手一看,白色的,样子很漂亮,真是很庆幸没有买TP-LINK或D-LINK那些黑色的砖头。

不过在设置的时候遇到了些麻烦。这个机器真是奇怪,说是无线路由,但是无线一开始是禁用的。必须要用有线方式把无线功能开启才行。于是照着说明书连好网线。因为我是在公司里面试,所以用的是固定IP的局域网。然后就搞出一系列稀奇古怪的问题,我在这里总结一下,希望对以后自己和别人都有用。

  • 设置页面进不去
这是第一个问题,IE总是处于返回状态,但是界面上面就是一片白。我感觉可能是插了外网的网线所致,所以把外网的网线拔了。然后再试,一下子就进去了。结论是:进控制界面最好拔了外网网线,如果不行就把路由断电,再重新开启。

  • 配IP
如果在局域网内就直接配置局域网IP,网关和DNS。配好之后按“测试”按钮,如果成功就能连到NETGEAR中国网站。

  • 什么都设置好了但是还连不上INTERNET
我运气不好,遇到的就是这种情况,结果只能死马当活马医,不管三七二十一直接RESET。这个RESET键可以看机器背后的示意图,就在WAN插口附近。按5秒左右就能重置。然后再设置一边。


信号强度。NETGEAR不愧是排名第二的厂商。质量要比公司自己用的TP-LINK好的多。我站在60米外,隔了3堵墙还有1~2个信号。看看页面是绝对可以了。