排序输入文件的内容并写入输出文件

时间:2019-01-11 14:00:59

标签: perl sorting file-io

我想对一个文本文件的内容进行排序,然后将其另存为另一个文本文件(或覆盖前一个文件)。我对perl不太满意,因此似乎无法弄清楚为什么此代码段不起作用。

   rank          1          2          3           4           5           6 rank_match
1:    3 -0.6264538  0.3295078  0.5757814 -0.62124058 -0.01619026  0.91897737  0.3295078
2:    4  0.1836433 -0.8204684 -0.3053884 -2.21469989  0.94383621  0.78213630 -0.3053884
3:    2 -0.8356286  0.4874291  1.5117812  1.12493092  0.82122120  0.07456498  1.1249309
4:    1  1.5952808  0.7383247  0.3898432 -0.04493361  0.59390132 -1.98935170  1.5952808

该代码应该在保持相同格式的同时对每一行进行排序。但是,当我运行它时,没有出现任何错误,但是找不到输出文件。

输入文件:

open(my $file, '>', $filename) or die $!;
print $file $string;

my @curOrd = qw( USD AUD BRL GBP CAD CNY DKK HKD INR IDR ILS JPY MXN NOK 
PHP PLN SGD SKK ZAR KRW SEK CHF TWD THB EUR MYR NZD SAR TRY RUB CZK AED CLP 
EGP MAD NGN OMR QAR );

my $curKnt = scalar @curOrd;
my $outfile = 'file1.txt';
my $infile = 'file2.txt';
open (OUTFILE, ">$outfile");

   foreach my $i (0..$curKnt) {
   open (INFILE, $infile);
   while(<INFILE>)
   {
        my @x= split(',', $_);
        print "x2 = $x[2]\n";
        print "cur_ord = $curOrd[$i]\n";
        if ($x[2] eq $curOrd[$i])  {
           print OUTFILE "$_";
        }
       @x=();
   }  # end of while

   close (INFILE);   

}  # end of foreach

close (OUTFILE);

输出文件:

20181231,USD,AED,3.6736
20181231,USD,AUD,1.4179
20181231,USD,BRL,3.8817
20181231,USD,CAD,1.3632
20181231,USD,CHF,0.9842
20181231,USD,CLP,694.7432
20181231,USD,CNY,6.8787
20181231,USD,CZK,22.4985
20181231,USD,DKK,6.5252
20181231,USD,EGP,17.9426
20181231,USD,EUR,0.8738
20181231,USD,GBP,0.7853
20181231,USD,HKD,7.8322
20181231,USD,IDR,14483.0392
20181231,USD,ILS,3.7554
20181231,USD,INR,69.5662
20181231,USD,JPY,110.0258
20181231,USD,KRW,1114.7559
20181231,USD,MAD,9.6044
20181231,USD,MXN,19.6584
20181231,USD,MYR,4.1383
20181231,USD,NGN,365.4984
20181231,USD,NOK,8.6848
20181231,USD,NZD,1.4902
20181231,USD,OMR,0.3858
20181231,USD,PHP,52.5907
20181231,USD,PLN,3.7581
20181231,USD,QAR,3.6734
20181231,USD,RUB,69.5418
20181231,USD,SAR,3.7533
20181231,USD,SEK,8.9336
20181231,USD,SGD,1.3637
20181231,USD,SKK,26.3251
20181231,USD,THB,32.4579
20181231,USD,TRY,5.2938
20181231,USD,TWD,30.6034
20181231,USD,USD,1.0000
20181231,USD,ZAR,14.4104

2 个答案:

答案 0 :(得分:2)

这在我测试时按预期工作。我只能建议存在一些本地问题,这些问题会阻止您打开和写入输出文件。如果您检查了open()的返回值并采取了适当的措施,就会发现问题出在哪里。

我已经采取了收紧某些代码的自由:

my @curOrd = qw( USD AUD BRL GBP CAD CNY DKK HKD INR IDR ILS JPY MXN NOK
                 PHP PLN SGD SKK ZAR KRW SEK CHF TWD THB EUR MYR NZD SAR
                 TRY RUB CZK AED CLP EGP MAD NGN OMR QAR );

my $outfile = 'file1.txt';
my $infile = 'file2.txt';
open (my $out_fh, '>', $outfile)
  or die "Cannot open $outfile: $!";

# Iterating over the values in a list is usually
# better than iterating over the indexes.
foreach my $cur (@curOrd) {
  open ($in_fh, '<', $infile)
    or die "Cannot open $infile: $!";

  while(<$in_fh>) {
    my @x = split(/,/);
    print "x2 = $x[2]\n";
    print "cur_ord = $cur\n";

    if ($x[2] eq $cur)  {
      print $out_fh $_;
    }
  }  # end of while

  close ($in_fh);
}  # end of foreach

close ($out_fh);

更新:如此多次打开和关闭输入文件的效率非常低。此版本将其打开一次,将数据拆分为二维数组,然后对其进行排序。

my @curOrd = qw( USD AUD BRL GBP CAD CNY DKK HKD INR IDR ILS JPY MXN NOK
                 PHP PLN SGD SKK ZAR KRW SEK CHF TWD THB EUR MYR NZD SAR 
                 TRY RUB CZK AED CLP EGP MAD NGN OMR QAR );

# Build a look-up table mapping currencies to their
# sort position
my $i = 0;
my %cur_lookup = map { $_ => $i++ } @curOrd;

my $outfile = 'file1.txt';
my $infile = 'file2.txt';
open (my $out_fh, '>', $outfile)
  or die "Cannot open $outfile: $!";

open(my $in_fh, '<', $infile)
  or die "Cannot open $infile: $!";

my @in_data = map { [ split /,/ ] } <$in_fh>;

print $out_fh
  map { join ',', @$_ }
  sort { $cur_lookup{$a->[2]} <=> $cur_lookup{$b->[2]} } @in_data;

close ($in_fh);
close ($out_fh);

答案 1 :(得分:1)

您的代码不起作用的原因是因为yare试图读取超出范围的数组的值。脚本在此时死亡。 要修复此问题,请添加$ curKnt-;

my $curKnt = scalar @curOrd;
$curKnt--;

脚本的另一个问题是,它会打开和关闭$ infile 30次以上,这不是一个好主意。我认为您应该重写代码以将$ infile一次读入数组或哈希,然后处理该数组或哈希。我会这样写:

use strict;
use warnings;

my @curOrd = qw( USD AUD BRL GBP CAD CNY DKK HKD INR IDR ILS JPY MXN NOK PHP PLN SGD SKK ZAR KRW SEK CHF TWD THB EUR MYR NZD SAR TRY RUB CZK AED CLP EGP MAD NGN OMR QAR );

my %data;
my $infile  = 'file2.txt';
my $outfile = 'file1.txt';

open (my $in, "<", $infile) || die "can't open $infile file"; 
while (my $line = <$in>) {
    push(@{$data{(split ',', $line)[2]}}, $line);
}
close $in;

open (my $out, ">", $outfile) || die "can't open $outfile file"; 
foreach my $curr (@curOrd) {
    foreach my $line (@{$data{$curr}}) {
        print $out $line;
    }
}
close $out;