Chinaunix首页 | 论坛 | 博客
  • 博客访问: 469379
  • 博文数量: 142
  • 博客积分: 4126
  • 博客等级: 上校
  • 技术积分: 1545
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-22 10:03
文章分类

全部博文(142)

文章存档

2011年(8)

2010年(7)

2009年(64)

2008年(63)

我的朋友

分类:

2008-12-11 17:14:33

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函数在定时方面的扩展。

阅读(525) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~