2010年6月3日星期四

在Gentoo下使用UTF-8

在Gentoo下使用UTF-8

内容:

1.  字符编码

什么是字符编码

电脑本身并不能识别文字。相反的,每一个字符都是用数字来表示的。在以前,因受电脑硬件所限,每一个用来表示字母和字符的数字集合(称作编码系统、编码或 者字符集)的大小都很有限。

字符编码的历史

最普遍的(至少最被广泛接受的)字符集是ASCII(American Standard Code for Information Interchange 美国信息互换标准代码)。很多人认为ASCII是最成功的软件标准。现代ASCII编码是在1986年(ANSI X3.4, RFC 20, ISO/IEC 646:1991, ECMA-6)被美国国家标准协会统一的。

ASCII被严格限制在7比特大小,即它会用7位二进制数的组合来表示数字,在十进制中范围是从0到127。他们包括了32个不可见的控制字符,大多数是 从0到31之间的范围,还有就是最后一个控制字符,位处127的DEL或删除字符。从32到126的都是可视字符:空格,标点,拉丁字母和数字。

ASCII中的第八位原来是用来作为校验的奇偶位。如果不需要的话则置为0。这意味着,每一个ASCII字符都可以用一个字节表示。

虽然在现代英语通讯中ASCII已经足够了,但是其他的欧洲语言中所包括的带重音标记的字符就不那么容易解决了。ISO 8859标准集就是开发出来解决这些需求的。它们向后和ASCII兼容,但是与ASCII不同,第八位没有被留空,而是用来给每一种编码增加127个字 符。ISO 8859的局限性很快就被发现了,现在已经有15种ISO 8859标准的变种(8859-1到8859-15)。在ASCII兼容的范围内的字节外,同样字节表示的字符会经常出现冲突。让字符编码交互性的状况更 加恶化的是杂,微软的某些西欧语言版本的Windows使用Windows-1252编码,而不是ISO 8859。这个编码是ISO 8859-1编码的超集,但是却有些不同。不过幸好,它们都和ASCII编码兼容。

在其他操作系统已经在为同一个语言使用不同字符集的情况下,如Shift-JIS和ISO-2022-JP,非拉丁文多字节编码——如日文韩文(以及在一 定程度上中文)所用的EUC(Extended Unix Coding)编码——的进一步开发,增加了更多的混乱。那些需要查看西里尔字符的用户需要在俄语和保加利亚语用的KOI8-R和乌克兰语用的KOI8- U,以及其他的西里尔编码体系如失败的ISO 8859-5编码和常见的Windows-1251字符集之间选择。所有的这些字符集几乎和ASCII的都有兼容问题(虽然KOI8编码把西里尔字符按照 拉丁顺序排列,这样如果第八位被去掉的话,这些字符一样可以在ASCII终端中通过翻译去解读。)

这带来了混乱,并且使多语言交互几乎成为不可能,尤其在字母表不同的情况下。还是让我们进入Unicode的世界。

什么是Unicode?

Unicode克服了传统字符集的单字节限制。它有17个"位面",每个位面有65,536个代码点,总共可以装下1,114,112个字符。第一个位 面,也叫"基本多文种平面"或BMP(Basic Multilingual Plane),包括了几乎所有你会用到的东西,很多人误认为Unicode是一个16位的字符集。

Unicode可以用多种方式去表示,但是两个最普遍的方法是UTF(Unicode Transformation Format,Unicode转换格式)和UCS(Universal Character Set,通用字符集)。跟在UTF后边的数字指定了一个单元中的比特数,而UCS则是字节数。因为UTF-8的整8位特性,她已成为最广泛使用的 Unicode文字交互手段,它也是本文的主题。

UTF-8

UTF-8是一个变长的字符编码,也就是说它会用1到4个字节去表示一个字符。1个字节的UTF-8字符是用来编码ASCII的,这样也就让它可以和 ASCII完全兼容。UTF-8意味着ASCII和拉丁字母在数据体积没有增加的前提下可以与之前的保存文本互通,因为都只用到了第一个字节。东方字符如 日文用户,很不爽得被分配到了更高的字节范围,因为这样会造成最多达50%的数据体积的扩大。

UTF-8能为你做什么

UTF-8允许你在一个符合标准的国际多文字环境中工作,代价仅仅是数据所占空间略微增大。UTF-8是在互联网上通过Email、IRC还有几乎其他所 有媒体传输非ASCII字符的首选方法。尽管如此,很多人还是认为在线交流用UTF-8是属于滥用。在某个讨论频道、邮件列表和新闻组中用非ASCII UTF8之前,最好先了解那里的人们对UTF-8的态度。

2.  Gentoo Linux中设置UTF-8

查找或建立UTF-8 Locale

现在你已经理解Unicode的原理了,可以在你的系统中开始使用UTF-8了。

使用UTF-8的初步要求是要有一个支持国家语言支持(NLS)的glibc。推荐的方法是设置文件/etc/locale.gen。关于如何使用这个文件并不在这个文档涉及的范围内,请参阅Gentoo 本地化指南

下一步,我们需要判断对应我们语言的UTF-8 locale是已经存在,还是需要去创建。

代码 2.1: 检查UTF-8 locale是否已经存在

(把"zh_CN"替换成你想要的locale设置)
# locale -a | grep 'zh_CN'
zh_CN
zh_CN.UTF-8

我们需要检查这条命令的输出里是否有以.UTF-8结尾的locale。如果 没有以.UTF-8结尾的,那么我们需要创建一个UTF-8兼容的 locale。

注意: 只有在没有你的语言所对应的UTF-8 locale的时候才运行以下命令。

代码 2.2: 创建一个UTF-8 locale

(把"zh_CN"替换成你想要的locale设置)
# localedef -i zh_CN -f UTF-8 zh_CN.UTF-8

另外一个指定UTF-8 locale的方法就是在文件/etc/locale.gen中 增添相应的locale,然后运行命令locale-gen生成需要的 locale。

代码 2.3: /etc/locale.gen中的一行

zh_CN.UTF-8 UTF-8

设置Locale

要使用新locale我们需要设置一个环境变量:LC_CTYPE(如果你也 想改变系统语言的话,请设置LANG变量)。设置它的方法也有很多种;有的人 倾向于只针对某一个用户设置UTF-8环境,这种情况下,他们需要在他们自己的~/.profile中 设置(如果用/bin/sh的话);如果用/bin/bash的话,就在 ~/.bash_profile或者~/.bashrc设 置。如果想要更多的信息以及最佳做法(best practices),请参阅本地化手册

其他人选择设置全局locale。有一种情况下作者特别推荐这样设置,就是在使用/etc/init.d/xdm的 时候。因为这个启动脚本会在 前面提到的任何shell启动文件被读取之前启动显示管理器和桌面,也就是说如果不设置全局locale,那么这个脚本启动时任何相关的环境变量都没有定 义。

全局locale设置应该保存在文件/etc/env.d/02locale中。 这个文件看起来应该和以下内容类似:

代码 2.4: /etc/env.d/02locale示例

(不用再说了,把你的locale代替掉"zh_CN.UTF-8")
LANG="zh_CN.UTF-8"

注意: 你也可以用LC_CTYPE代替LANG。关于LC_CTYPE影响到的 分类的信息,请阅读GNU locale页

下一步,必须要以之前的改动来更新环境变量。

代码 2.5: 更新环境变量

# env-update
>>> Regenerating /etc/ld.so.cache...
* Caching service dependencies ...
# source /etc/profile

现在,不带参数的运行locale命令,看看我们是否已经正确设置了环境变 量。

代码 2.6: 检查我们的新locale已经在环境变量里了

# locale
LANG="zh_CN.UTF-8"
LC_CTYPE="zh_CN.UTF-8"
LC_NUMERIC="zh_CN.UTF-8"
LC_TIME="zh_CN.UTF-8"
LC_COLLATE="zh_CN.UTF-8"
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

好了。你已经在使用UTF-8 locale了,下一步就是配置你的日常使用的应用程序了。

3.  应用程序支持

当Unicode刚开始在软件世界得到应用的时候,多字节字符集和用来写日常使用的程序的语言如C语言等不是很合拍。即使是今天,有的程序仍然不能正确处 理UTF-8。幸运的是,大多数都没问题!

文件名,NTFS和FAT

在内核选项中,有那么几个NLS选项,但是千万别被混淆了。大多数情况下,你只需要在内核中加入UTF-8 NLS支持,以及将默认NLS设置成utf8就可以了。

代码 3.1: UTF-8 NLS的内核配置步骤

File Systems -->
Native Language Support -->
(utf8) Default NLS Option
<*> NLS UTF8
(Also <*> other character sets that are in use in
your FAT filesystems or Joilet CD-ROMs.)

如果你想加载NTFS分区,你需要为mount指定一个nls=选项。如果你 计划加载FAT分区,你需要为mount指定一个codepage=选项。你 也可以在内核配置中为FAT设置一个默认的codepage。注意,mount命令中指定的codepage会 覆盖内核中的设置。

代码 3.2: 内核中的FAT设置

File Systems -->
DOS/FAT/NT Filesystems -->
(437) Default codepage for fat

你应该避免把Default iocharset for fat设置成 UTF-8,因为这个是不推荐的。相反,你可以在mount的时候加入选项utf8=true。要获取更多相关的信息,请参阅man mount和内核文档/usr/src/linux/Documentation/filesystems/vfat.txt

如果想改变文件名的编码,可以用app-text/convmv

代码 3.3: convmv使用示例

# emerge --ask app-text/convmv
(命令格式)
# convmv -f <当前编码> -t utf-8 <文件名>
(把iso-8859-1换成你想要的原始编码)
# convmv -f iso-8859-1 -t utf-8 文件名

如果想改变文件内容,那么请使用glibc提供的工具iconv

代码 3.4: iconv使用示例

(把iso-8859-1换成你想要的原始编码)
(检查输出是否合法)
# iconv -f iso-8859-1 -t utf-8 文件名
(要转换文件,你必须创建一个新文件)
# iconv -f iso-8859-1 -t utf-8 文件名 > 新文件名

app-text/recode也可以用来做这个事情。

系统终端

重要: 在终端用Unicode,你需要安装>=sys-apps/baselayout-1.11.9。(译注:此节只适用于非英文的其他西方文字,终端 里要使用中文需要安装zhcon)

在终端下开启UTF-8,你要编辑/etc/rc.conf并且设置UNICODE="yes",还要阅读该文件内相应的注释——如果你想完全发挥 Unicode的优点,那么一个覆盖范围足够广的字体是很重要的。为了不出错,请确保你已经按照第一章中所说的正确 的建立了一个Unicode locale。

一个名为KEYMAP变量应该指定一个Unicode键盘布局,此变量位于/etc/conf.d/keymaps中。

代码 3.5: /etc/conf.d/keymaps示例片段

(把"uk"替换成你自己键盘的布局)
KEYMAP="uk"

Ncurses和Slang

注意: 如果你没安装或者不用Slang的话,忽略这段中相关Slang的信息。

/etc/make.conf里边的全局USE标记中加入unicode是很明智的,然后再重新emerge sys-libs/ncursessys-libs/slang。Portage在升级你的系统时也会自动帮你搞定的。

代码 3.6: 升级你的系统

# emerge --update --deep --newuse world

我们还需要重新编译依赖这两个库的软件包,这样USE标记的改变就会被应用。我们用到的工具(revdep-rebuild) 是gentoolkit的一部分。

代码 3.7: 重新编译连接到ncurses或者slang的程序

# revdep-rebuild --soname libncurses.so.5
# revdep-rebuild --soname libslang.so.1

KDE,GNOME和Xfce

所有主流桌面环境都完全支持Unicode,除了之前已经提及的设置外也不需要进一步设置什么了。这是因为底层的图形工具包(Qt或GTK+2)已经支持 UTF-8。这样,所有由这些工具包写出来的程序都是原生的支持UTF-8的。

当然,也有例外,比如的Xlib和GTK+1。GTK+1需要在~/.gtkrc里边有一个iso-10646-1的字体设置,例如-misc-fixed-*-*-*-*-*-*-*-*-*-*-iso10646-1。 还有就是使用Xlib或者Xaw的程序需要有类似的设置,不然他们会罢工的。

注意: 如果你安装了Gnome控制中心的某个版本的话,就用它来设置好了。选任何一个iso10646-1的字体就可以了。

代码 3.8: 示例~/.gtkrc(为GTK+1)定义兼容Unicode的字体

style "user-font"
{
fontset="-misc-fixed-*-*-*-*-*-*-*-*-*-*-iso10646-1"
}
widget_class "*" style "user-font"

如果有一个程序同时支持Qt和GTK+2的图形界面,那么GTK+2的图形界面应该会更好的支持Unicode。

X11和字体

重要: x11-base/xorg-x11对Unicode的支持比XFree86 更好,极度推荐。

TrueType字体支持Unicode,而且Xorg自带的大多数字体都有很好的字符支持,不过显然这些字体不可能覆盖Unicode里的每一个字。要 为X提供东亚字符支持的话,记得在USE标记中加入cjk。很多其他的程序也 使用这个USE标记,所以有理由把它加入永久的USE标记。

还有,Porage树里有几个字体也支持Unicode。

代码 3.9: 可选:安装一些支持Unicode的字体

# emerge terminus-font intlfonts freefonts cronyx-fonts corefonts

窗口管理器和终端模拟器

不基于GTK或Qt的窗口管理器一般也会有很不错的Unicode支持,因为他们一般都用Xft库来处理字体的。如果你的窗口管理器不用Xft处理字体, 你仍然可以把之前提及的字体设置(即-misc-fixed-*-*-*-*-*-*-*-*-*-*-iso10646-1)作为Unicode字体使 用。

使用Xft并支持Unicode的终端模拟器较难获得。除了Konsole和gnome-terminal外,Portage中最好的选择就是x11-terms/rxvt-unicodexfce-extra/terminal gnustep-apps/terminalx11-terms/mlterm,或者编译时带了unicodeUSE的x11-terms/xterm并 且用uxterm启动。app-misc/screen在以screen -U启 动的时候也支持UTF-8,或者将以下内 容加入到~/.screenrc

代码 3.10: 支持UTF-8的~/.screenrc

defutf8 on

Vim,Emacs,Xemacs和Nano

Vim完全支持UTF-8,而且还有内置UTF-8文件检测。可以用:help mbyte.txt获取更多的信息。

Emacs 22.x以及更高的版本也完全支持UTF-8。Xemacs 22.x暂时还不支持组合字符。

低版本的Emacs和Xemacs也许需要安装app-emacs/mule-ucsapp-xemacs/mule-ucs,然后把以下内容加入到~/.emacs以支持UTF-8里的CJK(中日韩)语言。

代码 3.11: Emacs CJK UTF-8支持

(require 'un-define)
(require 'jisx0213)
(set-language-environment "Japanese")
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)

Nano从1.3.6版本以后都完全支持UTF-8的。

Shell

现在,bash通过GNU readline库完全支持Unicode。Z Shell(zsh)如果有unicodeUSE标志的话,也可以提供Unicode支持。

C shell,tcshksh完全不支持UTF-8的。

Irssi

Irssi完全支持UTF-8,虽然她还是要求用户去设置一个选项。

代码 3.12: 为Irssi开启UTF-8

/set term_charset UTF-8

那些对ASCII以外的字符不使用UTF-8字符集的频道,可以用/recode命 令来转换这些字符。输入/help recode可以获取更多信息。

Mutt

Mutt邮件用户代理有很不错的Unicode支持。你不需要在配置文件中加入任何东西就可以让Mutt支持UTF-8。如果你的配置文件(包括签名)都 是UTF-8编码的话,Mutt不需要任何修改就可以在Unicode环境中正确工作。

注意: 你也许还会在用Mutt阅读邮件的时候看到'?'。这是有人用的邮件客户端没有正确的指出所用的字符集。除了让他们好好配置邮件客户端之外似乎没什么别的 方法了。

可以参考Mutt Wiki获 取更多信息。

Man

Man是任何Linux机器都有的。为了确保man里的Unicode字符被正确渲染,文件/etc/man.conf中 的一行需要被替换:

代码 3.13: man.conf的Unicode支持

(原始的)
NROFF /usr/bin/nroff -Tascii -c -mandoc
(替换后)
NROFF /usr/bin/nroff -mandoc -c

elinks和links

这些是常用的基于文本的浏览器,我们看看怎么为它们打开UTF-8支持。对于elinkslinks,有两个方法,使用浏览器中Setup选项设置或者直接修改配置文件。要在 Setup选项中设置的话,首先用elinkslinks打开一个网站,然后按Alt+S进入Setup菜单,再选择Terminal选项,或者按T。下拉到最后一个选项UTF-8 I/O并且按回车选择它。然后保存并且离开菜单。links中你也许需要再按一次Alt+S然后按S来保存设置。要在配置 文件中改变,请看以下内容。

代码 3.14: 为elinks/links开启UTF-8

(elinks的话,编辑/etc/elinks/elinks.conf或者~/.elinks/elinks.conf,
把下面这行加入到文件里)

set terminal.linux.utf_8_io = 1

(links的话,编辑~/.links/links.cfg,把下面这行加入到文件中)
terminal "xterm" 0 1 0 us-ascii utf-8

Samba

Samba是一套为UNIX系统,如Mac,Linux和FreeBSD,而实现SMB(服务器消息块)协议的软件。这个协议有的时候也会被称作公共 Internet文件系统(CIFS)。Samba也包括了NetBIOS系统——Windows网络中用来文件共享的。

代码 3.15: 为Samba开启UTF-8

(编辑/etc/samba/smb.conf,把以下内容添加到[global]部分)
dos charset = 1255
unix charset = UTF-8
display charset = UTF-8

测试

Internet有很多UTF-8测试网站的。net-www/w3mnet-www/linksnet-www/elinksnet-www/lynx和 所有基于Mozilla的浏览器(包括Firefox)都支持UTF-8。Konqourer和Opera也完全支持UTF-8。

当使用那些纯文本Web浏览器的时候,一定要确保所在的终端也支持Unicode。

如果你看到某些字符显示为一个小方框并且中间有字母或者数字的,那么就是说你的字体没有UTF-8想要的相应的符号或者字型。所以就用一个方框代替,并且 里边是对应该字符的UTF-8的十六进制码。

输入法

Dead keys(在X中)可以用来输入一些不包括在你键盘上的字符。方法是按下你的右 Alt键(在有的国家也叫AltGr),同时按下一个回车以左的非字母键(修改键),然后松开他们,最后按一个字母键。这样Dead key应该会修改这个字母。在按下AltGr以及修改键的时候,也可以同时按下Shift键以进一步修改输入内容。

在X中开启Deak Keys,你需要一个支持它的布局。大多数欧洲布局都默认有Dead key支持的,但是,北美布局似乎并不是这样。虽然在一定程度上不同的布局有不一致的地方,但是简单的解决方法似乎就是例如直接指定"en_US"布局而 不是"us"布局。布局是在文件/etc/X11/xorg.conf里边设 置的,就像这样:

代码 3.16: /etc/X11/xorg.conf snippet

Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
Option "XkbLayout" "en_US" # 而不是仅仅 "us"
(其他 Xkb 选项可以放这里)
EndSection

注意: 如果你正使用北美布局或者一个Dead key看起来不起效的布局时才需要做之前的这个修改。欧洲用户的Deak keys应该是直接就可以用的。

这个修改要在X服务重新启动后才会生效。要是你想马上生效的话,用setxkbmap工 具。比如setxkbmap en_US

对Dead keys的描述也许通过例子是最简单的。虽然结果是根据locale而变化的,但是概念是不变的。下面的示例中的字符使用了UTF-8编码,所以你需要告 诉你的浏览器用UTF-8模式浏览,或者有一个已经配置好的UTF-8 locale。

同时按下键AltGr和键[,松开,再按键a,就可以得到字符ä。同时按下键AltGr和键[,松开,再按键e,就可以得到字符ë。同时按下键AltGr 和键;,松开,再按键a,就可以得到字符á。同时按下键AltGr和键;,松开,再按键e,就可以得到字符é。

同时按下键AltGr,Shift和[,松开,再按键a,得到一个北欧斯堪的纳维亚字符å。类似的,同时按下键AltGr,Shift和[,然后松开[,然后再按一下[,就可以得到˚。虽然看起来很像,但是这个(U+02DA)并不是度数那个 符号(U+00B0)。同理这个方法也可以用来输入dead key可以输入的其他重音符号——AltGr和[同时按,松开[,再按[就可以得到¨。

AltGr可以单独和字母键组合。比如,AltGr和m,可以组合出一个希腊小写字母mu:µ。AltGr和s组合出一个scharfes s或者esszet:ß。就像很多欧洲用户所期待(因为键盘上这么标明的)的,AltGr和4(或者E,取决于键盘布局)能输入一个欧元符号€。

资源

没有评论: