0

我从我的一位朋友那里得到了这段代码,但是因为我没有使用 perl,所以我不知道它是如何工作的。你能帮我理解吗?

该文件必须获得一个文件,其中包含一些显示延迟的数据并获得间隔内的累积分布函数。

#!/usr/bin/perl


#print "Starting converter on file $ARGV[0]\n";

if ($#ARGV < 2 || $#ARGV > 3) {
    print "Usage: ac_hist_gen.pl <input file> <num intervals> <output file> [ <interval size> ]\n";
    exit(-1);
}

open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";
open(outfile,">$ARGV[2]") || die "Couldn't open $ARGV[2] for writing.\n";

for ($i=0; $i< 100 / $ARGV[1]; $i++) {
    $dist[$i] = 0;
    $acum[$i] = 0;
}

$max=0;



if ($#ARGV == 2) {

while (<infile>) {

    if ($_ > $max) {
    $max=$_;
    }    
}

$intsize = $max / $ARGV[1];
} else {
    $intsize= $ARGV[3];
}

close(infile);



#print "size is $numpkts, max is $max, div is $intsize , test is $test\n";


open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";

while (<infile>) {

    $val = int($_ / $intsize);

    if (($_ / $intsize) == $val) {
    $dist[$val-1]++;
    } else {
    $dist[$val]++;
    }

#  print "val is $val\n";


}

for ($i=0; $i< $ARGV[1]; $i++) {
    $limit = ($i+1) * $intsize;
    $acum[$i]+= $dist[$i];
    $acum[$i+1] = $acum[$i];   
    print outfile "$limit $acum[$i]\n";
}


close(outfile);
4

2 回答 2

1

你得到的代码写得不是很好。这是一个修订版:

#!/usr/bin/perl

# pragmas
use strict;
use warnings;

# read command line arguments
if ($#ARGV < 2 || $#ARGV > 3) {
    print "Usage: perl $0 <input file> <num intervals> <output file> [<interval size>]\n";
    exit 1;
}
my ($input_file, $num_intervals, $output_file, $interval_size) = @ARGV;

# find interval_size if not specified
unless (defined $interval_size) {
    my $max = 0;
    process($input_file, sub { $max = $_[0] if $_[0] > $max });
    $interval_size = $max / $num_intervals;
}

# fill dist array
my @dist;
process($input_file, sub {
    my $q = $_[0] / $interval_size;
    my $val = int $q;
    $dist[$val == $q ? $val - 1 : $val]++;
});

open my $fh_out, '>', $output_file
    or die "cannot open (write) file '$output_file': $!\n";

# fill acum and generate output
my @acum;
for (0 .. $num_intervals - 1) {
    my $limit = ($_ + 1) * $interval_size;
    $acum[$_] += $dist[$_];
    $acum[$_+1] = $acum[$_];
    print $fh_out "$limit $acum[$_]\n";
}

close $fh_out;

#
# process 'filename', sub {
#     my ($line) = @_;
#     # do something with $line, it is chomped
# };
#
sub process {
    my ($file, $code) = @_;

    open my $fh, '<', $file
        or die "cannot open (read) file '$file': $!\n";

    local $_;
    while (<$fh>) {
        chomp;
        $code->($_);
    }

    close $fh;
}

问候, 马蒂亚斯

PS:我没有测试代码,但是 perl -c 可以。

于 2013-05-23T09:44:43.093 回答
1

好的,首先快速讨论 ARGV。这就像在 C 程序的 main() 声明中使用的 char **argv

perl 中的 ARGV 被隐式声明为数组。在 perl 中,我们像这样引用整个数组

@ARGV

和这样的数组大小

$#ARGV

并像这样对数组中的各个元素

$ARGV[0]

数组从零开始索引,$ARGV[0]数组@ARGV 的第一个元素也是如此

这就是程序的命令行参数是如何被读取的,这就是所有对 ARGV 的引用所关心的

下一项

open(infile,"$ARGV[0]") || die "Couldn't open $ARGV[0] for reading.\n";
open(outfile,">$ARGV[2]") || die "Couldn't open $ARGV[2] for writing.\n";

鉴于我刚刚与 ARGV 讨论过的内容,这是自我记录。这为输入和输出创建了一对文件句柄。双引号中提到的变量"被插入到它们的值中。因此,如果$ARGV[0]是“filename1.txt”,则"ARGV[0]"编译为“filename1.txt”

在 perl 中,除了数组之外,还允许使用简单的单值变量(称为标量)

$x=1类似于x=1C 中的。

然而,在 perl 中,可以在不分配内存的情况下分配字符串。这是自动的。字符串“类型”变量可以很容易地转换为数字。一个简单的变量可以从一个数字开始,然后转换为一个字符串,然后根据上下文自动返回一个数字。声明变量也不是强制性的!在 C 中你不得不说int x要声明它,这在 perl 中没有严格执行

下一段代码

for ($i=0; $i< 100 / $ARGV[1]; $i++) {
    $dist[$i] = 0;
    $acum[$i] = 0;
}

这与在 C 中的情况完全相同,只是变量前面有一些额外的 $ 符号,并且不需要声明数组 @dist 和 @acum 的大小或它们的类型

下一点要考虑

while (<infile>) {

    if ($_ > $max) {
    $max=$_;
    }    
}

infile是一个文件句柄,结构<infile>从文件中读取一行。但是您会注意到,在 perl 程序中读取数据的位置并不清楚。这里使用的 perl 技巧是有一个包含最后读取行的默认变量。变量是$_。所以这个循环所做的就是在文件中寻找最大值。

我现在跳过一点,直接走到最后

for ($i=0; $i< $ARGV[1]; $i++) {
    $limit = ($i+1) * $intsize;
    $acum[$i]+= $dist[$i];
    $acum[$i+1] = $acum[$i];   
    print outfile "$limit $acum[$i]\n";
}

这是一个对数组执行操作的循环,@acum类似于for上面的循环打印行写入输出句柄。变量如上所述进行插值。

希望这有助于您的理解

于 2013-05-23T09:30:23.237 回答