如何在<>

时间:2016-03-13 17:00:24

标签: perl vector sum filehandle

我有一个代码,可以在所有文件中添加所有向量。 可以有任意数量的输入文件。例如,第一个输入文件是:

0.55        0       0.3335      1.2
0.212       0       2.2025      1

,第二个是:

0.25        0       0.3333      1.0
0.1235      0       0.2454      1

我得到的是所有向量的总和,因此在结果中得到一个向量 这是:

1.13550     0       3.1147      4.2

但是我试图将第一个文件的第一个向量与第二个文件的第一个向量相加,依此类推。在根据这个例子的结果中,我应该得到2个向量。

现在我有了这个:

use strict;
use warnings;

if ($ARGV[0] ne "vector1.dat"){
    die ("vector1.dat is necessary as first argument");
}

my @sum = 0;
my $dim = 0;

while (<>) {

    #Ignore blank lines, hashtags 
    #and lines starting with $
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){
        next;
    }
    my @vectors = split(" ", $_);
    my $vector_length = @vectors;

    if ($dim eq 0) {
        $dim = $vector_length;
    } 
    else {
        if ($dim ne $vector_length) {
            die ("Vector dimensions do not match. : $!");
        }
    }
    for (my $i = 0; $i <= $#vectors; $i++) {
        $sum[$i] += $vectors[$i];
    }
}

$" = "\t\t";
print "\n --- \n @sum \n";

我需要的只是找出如何识别每个文件的第n行 并且要记住这些行的列值,可以有n个文件。 不过,我在这里看到了类似问题的文件处理问题 我没有找到答案。 只是寻找一些建议和指导。坚持这个。

3 个答案:

答案 0 :(得分:2)

自己打开每个文件并使用$.变量来了解您所在的行(或自己计算文件)。这是基本结构:

foreach my $file ( @files ) {
    open my $fh, '<', $file or die ...;
    while( <$fh> ) {
        chomp;
        $sum[ $. ] = ...;  # $. is the line number
        }
    }

如果您不喜欢$.,则可以使用其较长的名称。你必须打开English(Perl附带):

use English;
## use English qw( -no_match_vars );  # for v5.16 and earlier

foreach my $file ( @files ) {
    open my $fh, '<', $file or die ...;
    while( <$fh> ) {
        chomp;
        $sum[ $INPUT_LINE_NUMBER ] = ...;
        }
    }

或者,您可以自己计算,如果文件中的向量不是由严格的行号排列(可能是因为注释或其他格式化的奇怪),这可能会很方便:

foreach my $file ( @files ) {
    open my $fh, '<', $file or die ...;
    my $line = -1;
    while( <$fh> ) {
        $line++;
        chomp;
        $sum[ $line ] = ...;
        }
    }

更难的方法是the answer bart gives检查每一行末尾的eof,看看神奇的ARGV句柄是否正在查看新文件,如果是,则重置$.。这是一个有趣的伎俩,但几乎没有人会理解它在做什么(甚至注意到它)。

对于问题的其他部分,我认为你做的向量总和错误,或使用令人困惑的变量名称。线是矢量,线中的数字是组件。二维数组将起作用。第一个索引是行号,第二个索引是组件索引:

while( <$fh> ) {
    chomp;
    ... skip unwanted lines
    my @components = split;
    ... various dimension checks
    foreach my $i ( 0 .. $#components ) {
        $sum[ $. ][ $i ] += $components[ $i ];
        }
    }

Data::Dumper模块对于复杂的数据结构非常方便。您还可以查看perldsc(Perl数据结构手册)文档。 $.变量位于perlvar

答案 1 :(得分:0)

$.是最近读取的文件句柄的行号。 close(ARGV) if eof;可用于重置文件之间的文件编号(如eof中所述)。 (注意:eof()eof不同。)所以你现在有了行号。

您遇到的第二个问题是您正在向矢量($vectors[$i])添加矢量分量($sum[$i])。您需要向矢量组件添加矢量组件。首先使用更合适的变量名称。

这就是我们得到的:

my @sum_vectors;
while (<>) {
   s/#.*//;          # Remove comments.
   next if /^\s*$/;  # Ignore blank lines.

   my @vector = split;

   if ($sum_vectors[$.] && @{ $sum_vectors[$.] } != @vector) {
      die("$ARGV:$.: Vector dimensions do not match\n");
   }

   for my $i (0..$#vector) {
      $sum_vectors[$.][$i] += $vector[$i];
   }
} continue {
   close(ARGV) if eof;  # Reset line numbers for each file.
}

修复了另外两个错误:

  • $!在您使用它时没有任何有意义的内容。
  • 您忽略了包含评论的行,即使它们也包含有效数据。

答案 2 :(得分:-1)

试试这个:

#!/usr/bin/perl
use strict;
use warnings;

if ($ARGV[0] ne "vector1.dat"){
    die ("vector1.dat is necessary as first argument");
}

my %sum;
my $dim = 0;
my $vector_length;
my $line_number;

while (<>) {

    #Ignore blank lines, hashtags
    #and lines starting with $
    if ($_ =~ /#/ || $_ =~ /^$/ || $_ =~ /^\s$/){
        next;
    }
    my @vectors = split(" ", $_);
    $vector_length = @vectors;

    if ($dim eq 0) {
        $dim = $vector_length;
    }
    else {
        if ($dim ne $vector_length) {
            die ("Vector dimensions do not match. : $!");
        }
    }
    for (my $i = 0; $i <= $#vectors; $i++) {
        $sum{$.}{$i} += $vectors[$i];
    }
    $line_number = $.;
    $. = 0 if eof;
}

$" = "\t\t";
for (my $line=1; $line<=$line_number; $line++)
{
    print $line;
    for (my $vector=0; $vector<$vector_length; $vector++)
    {
        print " " . $sum{$line}{$vector};
    }
    print "\n";
}