快捷搜索:

学习使用Perl 5.8.6 中的Unicode 特性

只管到 Perl 6 中才传播鼓吹完全支持 Unicode,然则在 Perl 5.8.6 中内嵌的对 Unicode 的支持已经足以开始编写本地化的利用法度榜样了。Ted 应用自己所钟爱的编辑器 Yudit,先容了 Perl 若何读取、解释和处置惩罚 UTF-8 编码的 Unicode。

从 5.6.0 版本宣布以来,Perl 已经发生了极大年夜的变更。Perl 6 项目是在一个名为 Parrot 的说冥器(它内嵌了对 UTF-8 和很多其他与 Unicode 有关的特点的支持)的根基上构建和运行的(我知道这种说法太过简单,然则本文后面顿时要先容的内容可以确保您并不必要担心这些细节)。是以,Perl 6 从一开始就异常注重对 Unicode 的支持。(以是,在 Perl 6 宣布时我还会撰写别的一篇有关 Perl 6 的 Unicode 文章。我当然盼望这很快就可以实现。到时刻我就不会只是这么简单地提一下就算完了!)

在撰写本文时,我参考的是 5.8.6 版本,然则今朝最新版本是 5.8.7。我并没有对 CPAN 的任何 Unicode 模块进行测试 —— 只管这些模块切实着实存在,而且也可以很好地事情 —— 由于我们在本文中重点评论争论的是 Perl 中内嵌的对 Unicode 的支持特点。是以,我所测试的目标是 Perl 的 Unicode(UTF-8 编码)的读取、解释和处置惩罚能力。在本文中我也并没有评论争论 Unicode、UCS 和 UTF-8 编码的内容 —— 在 参考资料 中可以找到先容这个主题的富厚资本。

我爱好应用 Yudit 编辑器和 rxvt(Unicode 版本)的终端来进行有关 Unicode 的事情。(我不停在应用 rxvt,而不是 xterm;它们都可以很好地处置惩罚一些简单的工作,然则从我的不雅点来看,rxvt 要更好些,由于它可以应用多种字体来显示不合的字符集。)

Unicode 的筹备

为了这篇应用 UTF-8 编码的文章,我做好了所有的事情。您应该可以在大年夜部分今世 UNIX® 系统中安装 rxvt-unicode 终端包。您还必要确保支持一个 UTF-8 locale,这与 OS 有关。平日来说,您应该可以这样做:setenv LANG en_US.UTF-8; rxvt-unicode,然后就可以了;然则有些系统,例如 Debian Linux,可能必要其他一些步骤来启用 UTF-8 locale(平日它们默认是没有启用的)。别的, en_US.UTF-8 可能对付您来说并不是一个相宜的 locale。您可以反省自己的 OS 手册 和 HOWTO 文档。

您应该安装 Yudit 编辑器,它的功能异常强大年夜,而且异常轻易应用。您也可以应用 CVS 版本的 Emacs,我所应用的是 2005 年 1 月的版本(当前的稳定版本是 21.4)。Emacs 可以读写 UTF-8 编码的文件,在我的实验中都异常稳定 —— 只是对付高档的 Unicode 事情来说,功能没有 Yudit 强大年夜。

留意:在为本文供给的脚本中,已经 包括了 use strict; 和 use warnings; 附注(pragmas)(您可以从下面的 linux/l-cpunicode/#downloads">下载 部分下载 cp35.zip 文件,此中包孕有这些附注)。不停启用这些附注就不会呈现一些导致遗憾的差错。

打印 Unicode 字符

关于 Unicode,最基础的工作(也是最有用的工作)可能便是它让法度榜样可以打印越过 ASCII 和 Latin-1 字符集范围的字符。是以,若何打印 Unicode 字符呢?chr() 函数可以实现这种功能。例如,0x30A4 这天文中的一个片假名,它看起来就像是“T”,不过上面的横线是斜向上的:

图 1. 日文片假名字符“I”(“ee”)

要打印这个片假名,后面再跟上一个笑貌符号,可以输入:

perl -e'binmode(STDOUT, ":utf8"); print chr(0x30A4), chr(0x263a)'

留意 binmode() 调用。假如没有这个调用,或者等效的 -C 开关,Perl 就会打印一个打印语句中有宽数据的警告信息(具体信息请参阅 perldoc perlunicode 和 perldoc perlrun)。从我的不雅点来看,这只是 1% 的 Perl 用户必要应用的一个特点;其他 99% 的用户都必要忍受这个警告,或者额外编写一些代码来处置惩罚它。默认启用这个警告信息并不是什么好主见。

显然,假如您有很多器械必要输入,经由过程编码(或名字,Perl 也可以应用名字实现相同的功能)来指定字符其实是件苦楚的工作。若何才能以 UTF-8 的形式给 Perl 供给数据呢?script 2.pl 在脚本中就直接嵌入了 UTF-8 编码的数据。

这个脚本的事情与 HERE 文档类似。Script 3.pl 会分手以英语、保加利亚语和俄语来打印“您好”。

不幸的是,UTF-8 数据并不被支持作为 HERE 标记(marker)。是以,script 4.pl 会申报一个差错“Can't find string terminator \343 anywhere before EOF at ./4.pl line 7.”(此中 \343 是一个无关字符)。

这可太糟了;单个 Unicode 字符可以作为 HERE 标记。它是简短的、富有体现力的且不太可能呈现在文本中的字符(假如仔细选择的话。例如笑貌符号)。不幸的是,use utf8; 并不能应用 Unicode HERE 标记。

您可以给一个变量分配一个 HERE 文档,而不是简单地打印这个变量,这样就必要在脚本中应用 use utf8;。

识别 Unicode 字符

与打印 Unicode 数据相对的便是若何识别这些数据。内嵌的 ord() 函数若何履行?我在 脚本 5.pl 中对此一一进行了反省,它可以很好地事情。从编码到字符的映射是一对一的,从字符到编码的映射也是一对一的。这是一个异常简单但却异常紧张的测试;若何才能确保一个字符只会映射为一个惟一的编码呢?

在敕令行中应用任何编码(例如十进制的 500 或 1000)来运行 5.pl,结果如 5_out.txt 所示。

假如您所应用的编码与我在 5_out.txt 中应用的相同,就会留意到, 当编码太大年夜时,这个脚本就什么也没有做;这恰是我们期望的环境。在 5_out.txt 中,我应用单词 [GARBAGE] 来樊篱那些无用的输出信息,然则您可以随意运行这个脚本,并查看输出结果。

那么,我们应该若何识别敕令行中输入的 Unicode 数据呢?脚本 6.pl 可以识别 @ARGV 中的 UTF-8 数据(6_out.txt 显示了一个运行 6.pl 的样例输出)。

留意 -CA 开关(来自 perldoc perlrun),它奉告 Perl,@ARGV 中会包孕 UTF-8 数据。假如没有 -CA 开关,Perl 就会觉得输入数据是字符 199。还有,我履行了一个 join() 操作,然后又履行了一个 split(),将所有的 @ARGV 输入都变成字符数据。

是以,对付 Unicode 字符的识别就可以很好地处置惩罚内嵌的数据、天生的数据以及敕令行数据了。

匹配和存储 Unicode 数据

Unicode 数据可以应用正则表达式进行匹配。在 split() 调用中我们就已经应用了这种技巧,它可以匹配空字符串(它可以匹配任何地方,是以所匹配的字符串中的所有字符都邑一个一个地返回)。那么若何才能匹配单个字符呢?脚本 Script 7.pl 就可以匹配正则表达式中的 Unicode 字符(7_out.txt 给出了运行 7.pl 的样例输出)。

这个脚真相当简单,然则它却展示了正则表达式中的 . (period) 字符可以真正匹配 Unicode 字符。您可以在 foreach() 调用之前添加 use bytes; 来查看一些差错的行径。这会奉告脚本按照字节进行匹配,这样您就会看到 3 行输出,而不是 7_out.txt 中那样的两行输出。为什么是 3 行呢?记着 UTF-8 编码的数据是可变长的款式;450 处的 Unicode 字符在应用 UTF-8 进行编码时实际上只必要两个字节。

下一个样例脚本 8.pl 假定变量有一个 Unicode 名称,然则纵然像 perldoc utf8 文档所建议的那样指定了 use utf8,也会获得 Unrecognized character 差错。是以,就装作 $data 是笑貌符号好了。Unicode 文原先自于 unicode-sample.txt 文件,也包孕鄙人载文件中。

脚本 8.pl 可以精确匹配输入文本中的所有单词。假如您注释掉落第一个和第二个 foreach() 代码行,就会看到 Perl 对输入数据进行了排序。

脚本 9.pl 会将 Unicode 数据作为 hash 键来存储和读取。其事情道理就类似于 8.pl 应用 EOHIPPUS。

脚本 9.pl 在曩昔的 Perl 5.6 中并不能正常事情,是以我很痛快它现在可以正常事情了。

脚本 10.pl 也与 8.pl 一样, 不过它是将 Unicode 数据转换成大年夜写和小写的形式。

脚本 10.pl 可以完美地事情;所有的字母和重音符号都精确地转换了。

停止语

Unicode 的事情异常有趣,也异常有需要。只管今朝对 Unicode 的支持还不是太好,然则在接下来的 5 年中,法度榜样员的对象和编程体验中对 Unicode 的支持就会成为弗成或缺的。只管全部天下的联系越来越慎密,然则每个国家都不愿放弃自己的说话,是以法度榜样员的义务便是赓续适应这些变更。这不是说您应该进修新的说话,只管这相称有趣,也异常值得。简单的预期是,利用法度榜样可能必要进行本地化,并避免会将您限定到某一种说话的设计选择。例如,我们不能假定所有的文本都是从左到右排列的,也不能假定所有字符都是等宽的。

Perl 传统上就不停是一种面向文本的说话,是以 Unicode 支持改变了该说话的关键特点。正如本文先容的一样,5.8.6 版本的 Perl 可以很好地处置惩罚 Unicode。Perl 6 会为了处置惩罚 Unicode 而从头进行设计,是以我们可以期望能够得到 2 级或 3 级的技巧支持,而不像在 Perl 5 中只供给了部分的 1 级支持。

对 Unicode 支持的价值是处置惩罚数据时必要花费更长的光阴。法度榜样不再假设一个字节便是一个字符,是以所有的数据都必要从 UTF-8 进行解码,然后再从新编码成 UTF-8。(留意 Perl 5 可以支持其他编码;请参阅 perldoc encoding,然则 UTF-8 是 Unicode 中最盛行的一种编码,我也只保举应用这种编码)。

我建议您开始面对这种寻衅,并且编写能够处置惩罚 Unicode 的法度榜样。与量子谋略和遗传算法一样(我在 IBM 的 developerWorks 专栏中也先容了这两个主题的内容),我觉得对付将来的谋略寻衅来说,Unicode 是今朝最紧张的领域之一。

原文链接:http://www-128.ibm.com/developerworks/cn/linux/l-cpunicode/

您可能还会对下面的文章感兴趣: