#
用传统的 Unix 方式创建的简单用户界面
Unix 用户非常熟悉基于文本的 UI 模型。设想有一个 Perl
程序,让我们先看一下这个模型用于该程序的简单实现。标准的 Getopt::Std
模块简化了命令行参数的解析。这个程序仅仅为了说明 Getopt::Std 模块(没有实际用途)。
请参阅本文后面的参考资料。
使用 Getopt::Std 的命令行开关
#!/usr/bin/perl -w
use strict; # always use strict, it's a good habit use Getopt::Std; # see "perldoc Getopt::Std"
my %options; getopts('f:hl', \%options); # read the options with getopts
# uncomment the following two lines to see what the options hash contains #use Data::Dumper; #print Dumper \%options;
$options{h} && usage(); # the -h switch
# use the -f switch, if it's given, or use a default configuration filename my $config_file = $options{f} || 'first.conf';
print "Configuration file is $config_file\n";
# check for the -l switch if ($options{l}) { system('/bin/ls -l'); } else { system('/bin/ls'); }
# print out the help and exit sub usage { print <<EOHIPPUS; first.pl [-l] [-h] [-f FILENAME]
Lists the files in the current directory, using either /bin/ls or /bin/ls -l. The -f switch selects a different configuration file. The -h switch prints this help. EOHIPPUS exit; }
大家经常使用正则表达式的字符集从字符串中抽取或排除中文字符,但是这样做 很费事,效果也并不是很理想。实际上Perl从5.6开始已经开始在内部使用utf8编码 来表示字符,也就是说对中文以及其他语言字符的处理应该是完全没有问题的。关键 在于目前使用的编辑器以及文件格式并不都能很好地支持utf8,委屈了Perl的强大能力。 实际上我们只需要利用好Encode这个模块便能充分发挥Perl的utf8字符的优势了。
下面就以中文文本的处理为例进行说明(注意:编辑下面这段程序不能用使用utf8 编码的编辑器),比如有一个字符串"测试文本",我们想要把这个中文字符串拆成单个 字符,可以这样写: use Encode; use Encode::CN; #可写可不写 $dat="测试文本"; $str=decode("gb2312",$dat); @chars=split //,$str; foreach $char (@chars) { print encode("gb2312",$char),"\n"; } 结果大家试一试就知道了,应该是令人满意的。
这里主要用到了Encode模块的decode、encode函数。要了解这两个函数的作用我们 需要清楚几个概念: 1、Perl字符串是使用utf8编码的,它由Unicode字符组成而不是单个字节,每个utf8编 码的Unicode字符占1~4个字节(变长)。 2、进入或离开Perl处理环境(比如输出到屏幕、读入和保存文件等等)时不是直接使用 Perl字符串,而需要把Perl字符串转换成字节流,转换过程中使用何种编码方式完全取决 于你(或者由Perl代劳)。一旦Perl字符串向字节流的编码完成,字符的概念就不存在了 ,变成了纯粹的字节组合,如何解释这些组合则是你自己的工作。
我们可以看出如果想要Perl按照我们的字符概念来对待文本,文本数据就需要一直用 Perl字符串的形式存放。但是我们平时写出的每个字符一般都被作为纯ASCII字符保存( 包括在程序中明文写出的字符串),也就是字节流的形式,这里就需要encode和decode函 数的帮助了。
encode函数顾名思义是用来编码Perl字符串的。它将Perl字符串中的字符用指定的编 码格式编码,最终转化为字节流的形式,因此和Perl处理环境之外的事物打交道经常需要 它。其格式很简单: $octets = encode(ENCODING, $string [, CHECK]) 这里$string是Perl字符串,ENCODING是给定的编码方式,$octets则是编码之后的字节流 ,CHECK表示转换时如何处理畸变字符(也就是Perl认不出来的字符)。一般不需要使用 CHECK,让Perl按默认规则处理即可。 编码方式视语言环境的不同有很大变化,默认可以识别utf8、ascii、ascii-ctrl、 iso-8859-1等,中文环境(CN)增加了euc-cn(gb2312与之等价)、cp936(gbk与之等价 )、hz等,还有日文环境(JP)、韩文(KR)等等,在此不一一尽数。
decode函数则是用来解码字节流的。它按照你给出的编码格式解释给定的字节流,将 其转化为使用utf8编码的Perl字符串,一般来说从终端或者文件取得的文本数据都应该用 decode转换为Perl字符串的形式。它的格式为: $string = decode(ENCODING, $octets [, CHECK]) $string、ENCODING、$octets和CHECK的含义同上。
现在就很容易理解上面写的那段程序了。因为字符串是用明文写出的,存放的时候已 经是字节流形式,丧失了本来的意义,所以首先就要用decode函数将其转换为Perl字符串 ,由于汉字一般都用gb2312格式编码,这里decode也要使用gb2312编码格式。转换完成后 Perl对待字符的行为就和我们一样了,平时对字符串进行操作的函数基本上都能正确对字 符进行处理,除了那些本来就把字符串当成一堆字节的函数(如vec、pack、unpack等)。 于是split就能把字符串切成单个字符了。最后由于在输出的时候不能直接使用utf8编码 的字符串,还需要将切割后的字符用encode函数编码为gb2312格式的字节流,再用print 输出。
Encode模块的初步应用大概就是这样,详细情况还是要参阅模块的文档。实际上如果 我们使用UltraEditor等等支持编辑utf8编码文件的编辑器写程序,基本上用不着Encode 模块,在程序开头加上一句use utf8就行。这时Perl默认包括程序本身在内的所有的字符 都是Unicode字符,可以随便使用Unicode范围内的字符,甚至可以用非英文字符作为标识 符,只是输出的时候可能还需要用Encode模块。比如用UE的utf8编码模式编辑这个程序: use utf8; $单价=10; $数量=100; $总额=$单价*$数量; print "$总额\n"; 可以在Perl 5.6以后的版本中正常运行并给出结果,是不是很爽?:) 这种模式最大的优点 就是在字符串中可以混合多种语言的文字,就算中日韩英加上阿拉伯字符都在一个字符串 中出现也没问题;不像使用Encode模块那样必须固定一种编码方式,中日韩英字符同时出 现还好办,因为gbk包含了所有这些字符,可是再加上一些非亚洲语言字符就不一定能处 理了。所以以后用Unicode编码应该是大势所趋。
希望写的这些能对大家有所帮助。
这是我的windows下的emacs:
在P e r l中,d i e函数可以用来在出现错误的时候停止解释程序的运行,并输出一条有意义的 出错消息。正如你在前面已经看到的那样,只要调用d i e函数,就能够输出类似下面的消息: died at scriptname line xxx
d i e函数也可以带有一系列的参数,这些参数将取代默认消息而被输出。如果消息的后面 没有换行符,那么消息的结尾就附有at scriptname line xxx字样: die "Cannot open"; #prints "Cannot open at scriptname scriptname line xxx"
P e r l中有一个特殊的变量$ !,它总是设置为系统需要的最后一个操作(比如磁盘输入或输 出)的出错消息。当$ !用于数字上下文时,它返回一个错误号,这个号可能对任何人都没有 什么用处。在字符串上下文中, $ !返回来自你的操作系统的相应的出错消息: open(MYFILE, "myfile") || die "Cannot open myfile: $!\n";
不要使用$ !的值来检查系统函数的运行是失败还是成功。只有当系统执 行一项操作(比如文件输入或输出)之后, $ !才有意义,并且只有在该操作 运行失败后, $ !才被设置。在其他时间中, $ !的值几乎可以是任何东西,并 且是毫无意义的。
不过有时并不想使程序停止运行,只是想要发出一个警告。若要创建这样的警告, P e r l有 一个w a r n函数可供使用。w a r n的运行方式与d i e完全一样,你可以从下面这个代码中看出来,不过差别是它的程序将保持运行状态: if(! open(MYFILE, "output)) { warn "cannot read output: $!"; } else { ; # Reading output... }
1.split函数 %seen = ( ); $string = "an apple a day"; foreach $char (split //, $string) { $seen{$char}++; } 2./(.)/g 但是(.)永远不会是newline %seen = ( ); $string = "an apple a day"; while ($string =~ /(.)/g) { $seen{$1}++; } 3.unpack("C*")也可以逐个处理字符:(这个例子是累加字符串里每个字符ascii码的累加值) $sum = 0; foreach $byteval (unpack("C*", $string)) { $sum += $byteval; } print "sum is $sum\n"; # prints "1248" if $string was "an apple a day" $sum = unpack("%32C*", $string); #这个方法比上面更快,这个返回32位的checksum值. 4 .<>是默认的输入流,其实就是ARGV. 这个模拟sysv的checksum程序: #!/usr/bin/perl
# sum - compute 16-bit checksum of all input files
$checksum = 0;
while (<>) { $checksum += unpack("%16C*", $_) }
$checksum %= (2 ** 16) - 1;
print "$checksum\n";
Here's an example of its use: % perl sum /etc/termcap
1510 If you have the GNU version of sum, you'll need to call it with the —sysv option to get the same answer on the same file.
% sum --sysv /etc/termcap
1510 851 /etc/termcap 一个详细的例子:
#!/usr/bin/perl
# slowcat - emulate a s l o w line printer
# usage: slowcat [-DELAY] [files ...]
$DELAY = ($ARGV[0] =~ /^-([.\d]+)/) ? (shift, $1) : 1; #这里[.]取消了.的特殊性。使其为一般意义。shift移除了@ARGV第一个变量和长度减一。
$| = 1; #不为0就强行清空输出或打印。
while (<>) { #<>为@ARGV指定的文件句柄
for (split(//)) {
print;
select(undef,undef,undef, 0.005 * $DELAY); #select函数设置屏幕输出。这里是设置延迟。
}
}
下载 http://members.optusnet.com.au/puyo/ruby-mode.el 放入emacs/site-lisp目录
在.emacs中添加: (autoload 'ruby-mode "ruby-mode" "Major mode for editing ruby scripts." t) (setq auto-mode-alist (cons '("\\.rb$" . ruby-mode) auto-mode-alist)) (setq interpreter-mode-alist (append '(("ruby" . ruby-mode)) interpreter-mode-alist)) (setq load-path (append load-path '("X")))
perlcn - 简体中文 Perl 指南
欢迎来到 Perl 的天地!
从 5.8.0 版开始, Perl 具备了完善的 Unicode (统一码) 支援,
也连带支援了许多拉丁语系以外的编码方式; CJK (中日韩) 便是其中的一部份.
Unicode 是国际性的标准, 试图涵盖世界上所有的字符: 西方世界, 东方世界,
以及两者间的一切 (希腊文, 叙利亚文, 亚拉伯文, 希伯来文, 印度文,
印地安文, 等等). 它也容纳了多种作业系统与平台 (如 PC 及麦金塔).
Perl 本身以 Unicode 进行操作. 这表示 Perl 内部的字符串数据可用 Unicode
表示; Perl 的函式与算符 (例如正规表示式比对) 也能对 Unicode 进行操作.
在输入及输出时, 为了处理以 Unicode 之前的编码方式存放的数据, Perl
提供了 Encode 这个模块, 可以让你轻易地读取及写入旧有的编码数据.
Encode 延伸模块支援下列简体中文的编码方式 ('gb2312' 表示 'euc-cn'):
euc-cn Unix 延伸字符集, 也就是俗称的国标码 gb2312-raw 未经处理的 (低比特) GB2312 字符表 gb12345 未经处理的中国用繁体中文编码 iso-ir-165 GB2312 + GB6345 + GB8565 + 新增字符 cp936 字码页 936, 也可以用 'GBK' (扩充国标码) 指明 hz 7 比特逸出式 GB2312 编码
举例来说, 将 EUC-CN 编码的档案转成 Unicode, 祗需键入下列指令:
perl -Mencoding=euc-cn,STDOUT,utf8 -pe1 < file.euc-cn > file.utf8
Perl 也内附了 ``piconv'', 一支完全以 Perl 写成的字符转换工具程序, 用法如下:
piconv -f euc-cn -t utf8 < file.euc-cn > file.utf8 piconv -f utf8 -t euc-cn < file.utf8 > file.euc-cn
另外, 利用 encoding 模块, 你可以轻易写出以字符为单位的程序码, 如下所示:
#!/usr/bin/env perl # 启动 euc-cn 字串解析; 标准输出入及标准错误都设为 euc-cn 编码 use encoding 'euc-cn', STDIN => 'euc-cn', STDOUT => 'euc-cn'; print length("骆驼"); # 2 (双引号表示字符) print length('骆驼'); # 4 (单引号表示字节) print index("谆谆教诲", "蛔唤"); # -1 (不包含此子字符串) print index('谆谆教诲', '蛔唤'); # 1 (从第二个字节开始)
在最后一列例子里, ``谆'' 的第二个字节与 ``谆'' 的第一个字节结合成 EUC-CN
码的 ``蛔''; ``谆'' 的第二个字节则与 ``教'' 的第一个字节结合成 ``唤''.
这解决了以前 EUC-CN 码比对处理上常见的问题.
如果需要更多的中文编码, 可以从 CPAN (http://www.cpan.org/) 下载
Encode::HanExtra 模块. 它目前提供下列编码方式:
gb18030 扩充过的国标码, 包含繁体中文
另外, Encode::HanConvert 模块则提供了简繁转换用的两种编码:
big5-simp Big5 繁体中文与 Unicode 简体中文互转 gbk-trad GBK 简体中文与 Unicode 繁体中文互转
若想在 GBK 与 Big5 之间互转, 请参考该模块内附的 b2g.pl 与 g2b.pl 两支程序,
或在程序内使用下列写法:
use Encode::HanConvert; $euc_cn = big5_to_gb($big5); # 从 Big5 转为 GBK $big5 = gb_to_big5($euc_cn); # 从 GBK 转为 Big5
请参考 Perl 内附的大量说明文件 (不幸全是用英文写的), 来学习更多关于
Perl 的知识, 以及 Unicode 的使用方式. 不过, 外部的资源相当丰富:
-
http://www.perl.com/
-
Perl 的首页 (由欧莱礼公司维护)
-
http://www.cpan.org/
-
Perl 综合典藏网 (Comprehensive Perl Archive Network)
-
http://lists.perl.org/
-
Perl 邮递论坛一览
-
http://www.oreilly.com.cn/html/perl.html
-
简体中文版的欧莱礼 Perl 书藉
-
http://www.pm.org/groups/asia.shtml#China
-
中国 Perl 推广组一览
-
http://www.unicode.org/
-
Unicode 学术学会 (Unicode 标准的制定者)
-
http://www.cl.cam.ac.uk/%7Emgk25/unicode.html
-
Unix/Linux 上的 UTF-8 及 Unicode 答客问
the Encode manpage, the Encode::CN manpage, the encoding manpage, the perluniintro manpage, the perlunicode manpage
Jarkko Hietaniemi <jhi@iki.fi>
Autrijus Tang (唐宗汉) <autrijus@autrijus.org>
1.ord函数 $num = ord($char); #把字符转换为整数 2.chr函数 $char = chr($num); #把整数转换为字符 3.printf函数 printf("Number %d is character %c\n", 101, 101); #格式化输出一个整数和字符. printf "%vd\n", "fac\x{0327}ade";
102.97.99.807.97.100.101 printf "%vx\n", "fac\x{0327}ade";
66.61.63.327.61.64.65
4.unpack函数(C*把一个字符串转换为byte数组)(U*是指定的unicode) @ascii_character_numbers = unpack("C*", "sample");
print "@ascii_character_numbers\n";
115 97 109 112 108 101
5.pack函数(C*把一个byte数组转换为一个字符串) $word = pack("C*", @ascii_character_numbers);
$word = pack("C*", 115, 97, 109, 112, 108, 101); # same
print "$word\n";
sample
1.使用||来建立默认值 $foo = $bar || "DEFAULT VALUE"; #如果$bar没有值的话就使用"DEFAULT VALUE"作为$foo的值. $dir = shift(@ARGV) || "/tmp"; #如果没有参数,,就返回"/tmp". $dir = defined($ARGV[0]) ? shift(@ARGV) : "/tmp";
2.shift函数: 移出第一个数组元素,并返回.
3.defined函数: 判断一个变量、数组或数组的一个元素是否已经被赋值。expr为变量名、数组名或一个数组元素。如果已定义,返回真,否则返回假。 4. if和unless 注:if和unless意思相反! $a = $b if $a; #如果$a为真$a赋值为$b $a = $b unless $a #如果$a为假$a赋值为$b
1. 一旦我们读出了一个记录,通常打算去掉记录分隔符,(缺省值为换行符字符):
chomp($n = <STDIN>); 注: Perl 4.0版本仅有chop()操作,去掉串的最后一个字符, 不管该字符是什么。chomp() 没有这么大的破坏性,如果有行分隔符存在,它仅去掉行分隔符。如果你打算去掉行分隔符,就用chomp() 来代替chop()。
2.q//和 qq//前面一个是加单引号,后面一个是加双引号.匹配形式是 /regex/ 而直接运行命令是( $x=`cmd`). $string = q[Jon 'Maddog' Orwant]; # literal single quotes $string = q{Jon 'Maddog' Orwant}; # literal single quotes $string = q(Jon 'Maddog' Orwant); # literal single quotes $string = q<Jon 'Maddog' Orwant>; # literal single quotes
3.特殊字符包括 "\n" (新行), "\033" (八进制数的字符33), "\cJ" (Ctrl-J), "\x1B" (十六进制的字符 0x1B).
4.直接输入多行: $a = <<"EOF"; #指明了EOF为结束符 This is a multiline here document terminated by EOF on a line by itself EOF 5.prinf函数 $char = chr(0x394); $code = ord($char); printf "char %s is code %d, %#04x\n", $char, $code, $code; # %#04x表示占四位十六进制数少的话用0补齐
charDis code 916, 0x394
6.substr函数 substr函数形式如下: $value = substr($string, $offset, $count);
$value = substr($string, $offset);
substr($string, $offset, $count) = $newstring;
substr($string, $offset, $count, $newstring); # 和前面一样 substr($string, $offset) = $newtail; $string = "This is what you have"; # you can test substrings with =~
if (substr($string, -10) =~ /pattern/) {
print "Pattern matches in last 10 characters\n";
}
# substitute "at" for "is", restricted to first five characters
substr($string, 0, 5) =~ s/is/at/g; # exchange the first and last letters in a string
$a = "make a hat";
(substr($a,0,1), substr($a,-1)) =
(substr($a,-1), substr($a,0,1));
print $a;
take a ham
7.unpack函数 # extract column with unpack
$a = "To be or not to be";
$b = unpack("x6 A6", $a); # skip 6, grab 6
print $b;
or not
|