Perl学习
Posted 生物文摘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Perl学习相关的知识,希望对你有一定的参考价值。
7 使用外部模块、函数库或包
7.1 use Getopt::Std
我们使用其它 Unix 工具时发现, 有些工具可以带很多参数, 如:
$ split -l 100 -a 3 tmpfile
像上面的 -l , 可以用来指定一个参数, 并且还可以写成:
$ split -a 3 -l 100 tmpfile
这样, 我们就不需要担心参数的顺序问题了.
在 c 中, 我们使用 getopt 来处理参数(见 man 2 getopt),
而 Perl 一样提供了类似的东西, 使用起来也很简单:
use Getopt::Std;
getopt("bc:d:f:", \%arg);
# $arg{b}, $arg{c}
for (keys %arg) {
print qq/\$arg{$_} = $arg{$_}\n/
}
if ($arg{b}) {
print "-b\n";
}
$ perl t.pl -c /tmp -d /path/to/dir -f file-b
7.2 use POSIX
1. 时间处理
===========
在Perl 中, 时间处理与 C 语言里很相似, 使用下列同名函数:
time, localtime,mktime
a. time 得到当前秒数, 如 $curr =time;
b.localtime 返回秒数的具体描述列表, 若不指定参数, 则取当前时间.
如: ($sec,$min,$hour,$mday,$mon,$year) = localtime($t);
注意返回列表中的取值范围是与 localtime(3) 中的 struct tm 一样的,
也即:
$sec 0 -> 59
$min 0 -> 59
$hour 0 -> 23
$mday 1 -> 28 或 29 或 30 或 31
$mon 0 -> 11
$year 年份减去 1900, 如 107 表示 2007 年
因为返回是一个列表, 所以可以这样使用: @m =localtime($t);
但是, localtime 并不是只是返回这 6 个元素, 还有其它的另外的
三个值, 如星期几, 这些通常用不到. 见: perldoc -f localtime
c. mktime 返回秒数, 功能与 localtime 相反.
因 mktime 并不是 Perl 的内置函数, 而是放在模块 POSIX 中的,
所以需要这样使用:
use POSIX;
$t =mktime($sec, $min, $hour, $mday, $mon, $year);
或者:
$t =POSIX::mktime($sec, $min, $hour, $mday, $mon, $year);
输入参数列表的范围与 localtime 的返回值一样.
这样, 由 time,localtime, mktime 就能够完成所有的时间处理了.
1.2 例 2: 计算两个时间的差
有时需要计算两个给定时间的差, 或者某个时间的增量或减量,
这时需要把给定的时间先转成秒数, 再相加或相减.
例子: 计算 2007-06-0812:00:00 与 2007-05-3012:00:00 的差:
先写个简单的函数转成秒数:
use POSIX;
sub str2t($) {
my @m = split /[\-\s:]+/, $_[0];
@m[0, 1] = ($m[0] - 1900, --$m[1]);
mktime reverse @m
}
$t1 ='2007-06-08 12:00:00';
$t2 ='2007-05-30 12:00:00';
$tmp =str2t($t1) - str2t($t2);
1.3 例 3: 计算某个时间的偏移
例子: 计算 2007-6-812:0:0 的下一天或前一天:
先由 sub str2t 得到秒数, 加或减 86400 即可:
$t1 = '2007-6-812:0:0';
$next_day =str2t($t1) + 86400; # 一天的秒数是 86400
$prev_day =str2t($t2) - 86400;
printt2str($next_day), "\n";
1.4 例 4: 计算某月的最后一天
----------------------------
方法: 先得到下个月 1 日的秒数, 减去 86400, 即最后一天的秒数
8 引用补充
8.1 引用简介
8.2 使用引用
8.3 使用反斜线(\)操作符
8.4 引用和数组
关于Perl语言应该记住的最重要的一点可能是:Perl中的数组和哈希表始终是一维的。因此,数组和哈希表只保存标量值,不直接存贮数组或其它的复杂数据结构。数组的成员要么是数(或字符串)要么是引用。
对数组和哈希表可以象对简单变量一样使用反斜线操作符,数组的引用如下:
1 #!/usr/bin/perl
2 #
3 # Using Array references
4 #
5 $pointer = \@ARGV;
6 printf "\n Pointer Address of ARGV = $pointer\n";
7 $i = scalar(@$pointer);
8 printf "\n Number of arguments : $i \n";
9 $i = 0;
10 foreach (@$pointer) {
11 printf "$i : $$pointer[$i++]; \n";
12 }
9 实例应用
9.1 简单的 hash 应用
6.1 按关键字累加
假设有一文件 tmpfile 的内空是
aaa 5
bbb 22
ccc 2
aaa 10
我们需要按第一列为关键字累加第二列的值:
open(FH, "tmpfile") or die $!;
while ($line = <FH>) {
chomp $line; # 去掉换行
@m = split / /, $line; # 按空格分割
$hash{$m[0]} += $m[1]; # 累加
}
for $key(sort keys %hash) {
print "$key = ", $hash{$key},"\n";
}
9.2 大数问题
先看一下这一小段代码:
$n =1239482349287349;print $n, "\n";
输出结果为: 1.23948234928735e+15
这明显不是我们想要的, 当数在一个 double 的范围也即 8 字节之内,可以这样输出: printf "%.f", $n;这样结果就正确了。但是,当数很大时, 例如 $n = 123456789012345678901234 时, 用上面的方法输出结果并不是我们想要的, 这时彻底的解决方法是使用模块bignum :
use bignum;
$n =123456789012345678901234;
print $n,"\n";
这样的结果才是我们想要的.
9.3 一行的 perl
$ perl -pi -e 's/aa/bb/g' file1
解释: -pi 用于对文件作替换, s/aa/bb/g 把 $_ 中的全部 aa 替换成 bb,当使用 -pi 时, perl 对 $_ 做了一些处理, 凡是对 $_ 所做的修改,最终会写回文件, 所以, 可以只对部分做替换: $ perl -pi -e 's/aa/bb/gif /xx/' file1;
$ find . -name "file*" -exec perl-pi -e 's/aa/bb/g' {} \;
这个命令使用 find 查找当前目录所有的以 "file" 开头的文件,然后调用(用 -exec 参数) perl 完成替换.
$ ls | perl -ane'`mv $F[0] ..`if/200801/'
注解: -a 会让 perl 自动使用 split /\s+/ 分割每一行, 结果放到 @F 中.
9.4 在一个文件中找出在另一文件存在的行
功能: 假设有两个手机号码文件 A 和 B, 从 A 中找出在 B 中的号码
方法: 对 B 做 Hash, 过一遍 A 即可.
先生成文件 A:
$ perl -e 'srand(time); printf"13900%06d\n",
int(rand(10**6)) for 1..10000' > A
再生成文件 B:
$ perl -e 'srand(time); printf"13900%06d\n",
int(rand(10**6)) for 1..10000' > B
查找代码:
$fileb = shift;
open FH, $fileb or die $!;
while (<FH>) {
chomp;
$h{$_} = 1;
}
while (<>) {
chomp;
print $_, "\n" if $h{$_} ==1;
}
把上面的代码存为 t.pl,然后这样运行: perlt.pl B A或者运行: perlt.pl test1:/home/perl/3.1.2 test1:/home/perl/3.1.2; 注解: int 是一个内置函数, 功能是转成整型, 例如 int(6.4) 返回 6,而 rand 用于产生随机数, 需要先调用 srand 设置种子, time 返回当前秒数, 关于时间的使用请见 4.perl.3.txt .
9.5 计算目录特定文件的总字节大小
#!/usr/bin/perl
use File::Find;
my $dir = shift;
sub count {
if (-f and /^\.txt/) {
$size += -s;
}
}
find(\&count, $dir);
print $size, "\n";
9.6 把文件移到另外的目录
use strict;
my $dir = shift;
my $to = shift;
opendir DIR, $dir or die "$dir:$!";
while (my $file = readdir(DIR)) {
if (not $file =~ /^\./) {
rename "$dir/$file", "$dir/$to" or die $!;
}
}
close DIR;
9.7 这个子程序是寻找@names 中“dino”的索引值
my @names = qw /fred barney betty dino Wilma pebbles bam-bamm/;
my $result = &which_element_is(“dino”,@names);
sub which_element_is{
my($what,@array) = @_;
foreach(0..$#array){ #@array元素的索引
if($waht eq $array[$_]){
return $_; #找到既返回
}
}
-1; #没有找到元素(此处是可选的)
}
2.7.3 here 文档
here 文档定义一个字结束符用紧接着<<的符号定义,这个符号可以用双引
来。同时符串,这个符号可以用双引号或单引号括起来,同时它支持插值。例如下例:
my $Price = 'right';
#here documents
Print << eof
The price is $Price.
eof
将打印出:
The price is right.
Here 文档仅仅是引号的一种可替代的形式
文档。在你可以使用单引号或者双引号的地方就
可以使用 here 。下面是一个生成html文档的例子
use strict;
my someURL =http://www.location.com;
my $html =<<ENDHTML
<HTML>
<BODY>
A HREF= ge</A></P>
</BODY>
</HTML>
ENDHTML
Open (DATAFILE, ">data.file")"could not open 'data.file' $!";
Print DATAFILE $html; to file
close(DATAFIL);
my $s
'http://www.perl.com';
NDHTML;
<P><
"$someURL">Perl Homepa
ENDHT
open(DAprint DA || die $! # print
E);
print $html; # print to STDOUT
(素材来自网络)
以上是关于Perl学习的主要内容,如果未能解决你的问题,请参考以下文章