1.1.1 提出问题
你想逐个处理字符串的字符
1.1.2 解决方案
split使用空的模式就可以把字符串分割成单个字符,或者使用unpack函数,如果你只是想要字符的值的话:
@array = split(//, $string); # 每一个元素是一个字符
@array = unpack("U*", $string); # 每一个元素是一个unicode的code point码
#或者在循环里面逐个取出来:
while (/(.)/g) {
# $1 是字符, ord($1)是它的编码数字
}
|
1.1.3 讨论
前面我们已经讲过,Perl的基本单位是字符串而不是字符。很少需要逐个处理字符串的字符。通常情况下使用Perl的一些较高等级的操作符比如模式匹配等来处理问题更方便。比如你可以在7.14这一节里面看到怎么样使用一组替换来得到命令行的每个参数。
用可以匹配空字符串的模式去split一个字符串会得到一组字符列表。这是一个方便的特性如果你是有意为之。但是你也容易这样造成无意之失。举个例子,/X*/匹配所有可能的字符串包括空字符串。你可能会发现一些出乎你意料的其他东西。
下面这个例子打印了字符串"an apple a day"里面的每个字符,按照字符的升序打印:
%seen = ( ); $string = "an apple a day"; foreach $char (split //, $string) { $seen{$char}++; } print "unique chars are: ", sort(keys %seen), "\n"; # $>unique chars are: adelnpy
|
split跟unpack都是返回一个你需要的数组,如果你不是要一个数组的话,使用一个/g标志的模式匹配可以在循环里面逐个的取出字符:
%seen = ( ); $string = "an apple a day"; while ($string =~ /(.)/g) { $seen{$1}++; } print "unique chars are: ", sort(keys %seen), "\n"; # $>unique chars are: adelnpy
|
一般来说,如果你发现你正在逐个的处理字符,那么可能还有其他更好的方法。比起用index跟substr或者用split跟unpack,用模式匹配会更加容易。正如下面一个例子所展示的,用unpack函数来计算32bit的校验和比起手算有效率多了。
下来这个例子在一个循环里面计算一个字符串的校验和。有很多其他更好的计算校验和的方法,这里用到的只是一种传统的容易计算的校验和的基础算法。你如果要一个更强大的校验和你可以使用标准模块Digest::MD5(在Perl 5.8版本以后这是个标准模块,你也可以从CPAN里面取得):
$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);
|
下面这个效仿了SysV里面的校验和程序:
#!/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";
|
这样使用它:
% perl sum /etc/termcap1510
如果你有GNU版本的sum程序,你只需要给它一个-sysv的执行选项就可以得到跟上面程序一样的结果。
% sum --sysv /etc/termcap
$>1510 851 /etc/termcap
像下面这个例子里面的slowcat 小程序,它每次只处理输入字符串的一个字符。它每次打印出一个字符后都会停顿一下,这样它就能慢慢的滚动字符串,让读者有足够的时间去阅读显示的字符串:
#!/usr/bin/perl
# slowcat - emulate a s l o w line printer
# usage: slowcat [-DELAY] [files ...]
$DELAY = ($ARGV[0] =~ /^-([.\d]+)/) ? (shift, $1) : 1; $| = 1; while (<>) { for (split(//)) { print; select(undef,undef,undef, 0.005 * $DELAY); } }
|
1.2.4 参考
split和unpack函数的请参考perlfunc(1)和大骆驼书29章;在菜单3.10里面解释了select函数在定时方面的扩展。
阅读(578) | 评论(0) | 转发(0) |