首页›分类文章›计算机技术›perl 程序开发›perl study()函数详解

perl study()函数详解

计算机技术 · perl 程序开发2013-05-190次浏览0 个评论

study()函数花了一些额外的时间用在研究 SCALAR 上,预测在进行下一次修改之前要做的匹配次数。用法如下:

text
study SCALAR
study

这么做也许能但也许不能节约时间,具体情况取决于你正在搜索的模式的天性和数量,以及待搜索字串中字符出现频率的分布——你可能需要比较有它和没它的运行时间来看看哪个运行得快一些。那些扫描许多常量字串(包括在更复杂的模式里的常量部分)的循环会从 study 中得到最大好处。如果你的所有模式匹配都是前面有锚符号的常量字串,那么 study 一点忙都帮不上,因为那里没有扫描。你每次只能拥有一个 study——如果你研究另外一个标量的话,那么前面那个就“没有研究” 了。
study 运转的方法是:做一个包含待搜索字串中的每个字符的链表,因此,打个比方,我们就知道了所有的“k”字符的位置。从每个搜索字串里选出最少见的字符,这是基于从一些 C 程序和英文文本构造出来的频率统计表的。只对那些包含这个最少见字符的位置进行检查。
比如,下面是一个循环,它在每个包含特定模式的行前面插入一个生成索引的记录:

perl
while(<>) {
  study;
  print ".IX foo\n"      if /\bfoo\b/;
  print ".IX bar\n"      if /\bbar\b/;
  print ".IX blurfl\n"      if /\bblurfl\b/;
  ...
  print;
}

为了搜索 /\bfoo\b/,只查看 $_ 里的那些包含“f”的位置,因为“f”比“o”少见。除了在病态的情况下,这样做是很有优势的。唯一的问题是它是否能节约比先制作链表花的时间更多的时间。
如果你必须搜索那些你直到运行时才知道的字串,那么你可以把整个循环作成一个字串然后 eval 它以避免每次都要重新编译你的模式。再通过设置 $/ 把整个文件输入成一条记录,把这些组合起来可以非常快,通常比那些专业程序,象 fgrep(1) 什么的都快。下面的程序扫描一个文件列表(@files),搜索一个单词列表(@words),并且把那些包含大小写无关匹配的文件名字打印出来:

perl
$search = 'while (<>) { study;';
foreach $word (@words) {
  $search .= "++\$seen{\$ARGV} if /\\b$word\\b/i;\n";
}
$search .= "}";
@ARGV = @files;
undef $/;      # 吃进整个文件
eval $search;      # 这里运行程序
die $@ if $@;      # 处理 eval 失败
$/ = "\n";      # 恢复正常的输入终止符
foreach $file (sort keys(%seen)) {
  print "$file\n";
}

既然我们有 qr// 操作符,那么上面的编译完的运行时 eval 看上去没有必要。下面的做相同的事情:

perl
@pats = ();
foreach $word (@words) {
  push @pats, qr/\b${word}\b/i;
}
@ARGV = @files;
undef $/;      # 吃进每个完整的文件
while (<>) {
  for $pat (@pats) {
	 $seen{$ARGV}++ if /$pat/;
  }
}
$/ = "\n";      # 恢复正常的输入终止符
foreach $file (sort keys(%seen)) {
  print "$file\n";
}

评论

0

评论加载中…

发表评论

0/2000