读取文件,匹配字符串并格式化Perl中的输出

时间:2014-06-25 14:10:23

标签: excel perl csv

花了很长时间,现在它正在伤害我的头脑。我已经简化了数据文件,但基本上我有5个不同文件中的一些值,现在想要将它们绘制成excel。因此,线图的excel格式需要更正。

当前文件看起来像

Report-20140521.csv: Sun, 20
Report-20140530.csv: Sun, 23
Report-20140606.csv: Sun, 24
Report-20140613.csv: Sun, 25
Report-20140621.csv: Sun, 21
Report-20140521.csv: Mon, 22
Report-20140530.csv: Mon, 23
Report-20140606.csv: Mon, 24
Report-20140613.csv: Mon, 24
Report-20140621.csv: Mon, 21
Report-20140521.csv: Tues, 22
Report-20140530.csv: Tues, 23
Report-20140606.csv: Tues, 20
Report-20140613.csv: Tues, 21
Report-20140621.csv: Tues, 21

我想把这一切弄平,并且每行都有五行代码: -

                 Sun Mon Tue wed ..

Report-20140521.csv: 20  22  22
Report-20140530.csv: 23  23  23 
Report-20140606.csv: 24  24  20
Report-20140613.csv: 25  24  21
Report-20140621.csv: 21  21  21

已经研究过使用数组和数组数组,但无论哪种方式,数据似乎都被操纵,并且无法使用5条不同的线来平滑数据。除此之外,我需要保留文件名,因为这将在以后的Excel中条带化为日期格式。

3 个答案:

答案 0 :(得分:0)

我认为哈希的散列对此很有效,因为你的星期值是离散的和有限的。一些变体可能有用:

use strict;

my %matrix;

open IN, 'yourfile.txt' or die $!;
while (<IN>) {
  chomp;
  my ($report, $val) = split /,/;
  my ($file, $dow) = split /: /, $report;

  $matrix{$file}{$dow} = $val;
}
close IN;

my @dow = qw(Sun Mon Tues Wed Thu Fri Sat);

foreach my $file (sort keys %matrix) {

  print $file, "\t";

  my $report_ref = $matrix{$file};

  foreach my $dow (@dow) {
    print $$report_ref{$dow}, "\t";
  }

  print "\n";
}

示例输出:

Report-20140521.csv      20      22      22
Report-20140530.csv      23      23      23
Report-20140606.csv      24      24      20
Report-20140613.csv      25      24      21
Report-20140621.csv      21      21      21

答案 1 :(得分:0)

您可以使用数组散列来存储数据,然后打印出与您的列名匹配的值(即白天):

use warnings;
use strict;

open my $in, '<', 'in.txt';

my (%data, @record, @day, @n);

while (<$in>){
    chomp;
    my @split = split(/\s/);
    push @record, $split[0];
    $split[1] =~ s/,//g;        
    push @day, $split[1];
    push @n, $split[2];
}

push @{$data{$record[$_]} }, [ $day[$_], $n[$_] ] for 0 .. $#record;

my @days = qw(Sun Mon Tues Wed Thu Fri Sat);

print "$_ " foreach (@days);
print "\n";

for my $report (sort keys %data){
    print "$report\t";
    for my $val (@{$data{$report}}){
        my ($day, $n) = @$val;
        foreach(@days){
            print "$n\t" if $day eq $_;
        }
    print "\n"; 
        }
}

输出:

Sun Mon Tues Wed Thu Fri Sat  
Report-20140521.csv:    20  22  22  
Report-20140530.csv:    23  23  23  
Report-20140606.csv:    24  24  20  
Report-20140613.csv:    25  24  21  
Report-20140621.csv:    21  21  21

答案 2 :(得分:0)

此解决方案按您的要求执行。它使用散列%headers在读入数据时将日期名称转换为列号,并生成由CSV文件名称键入的散列。哈希值是值对的数组,每对由列号和该列的值组成

将数据消化到散列后,将按文件名的排序顺序进行扫描。数组@info初始化为七个空字段,哈希中的列/值对用于覆盖提供的列

确定文件名的最大长度,并在打印@headers日期名称数组时首先使用,然后使用每个哈希条目的@info数组

我希望这会有所帮助

use strict;
use warnings;

use List::Util 'max';
my $filename = 'current.txt';

open my $fh, '<', $filename or die qq{Unable to open "$filename" for input: $!};

my @headers = qw/ Sun Mon Tue Wed Thu Fri Sat /;
my %headers = map { $headers[$_] => $_ } 0 .. $#headers;

my %file_data;

while (<$fh>) {
  next unless my @fields = /(\S[^:]+:)\s+(\w{3})\w*, (\d+)/;
  my $file = shift @fields;
  $fields[0] = $headers{ucfirst lc $fields[0]};
  push @{ $file_data{$file} }, \@fields;
}

my $width = max map length, keys %file_data;
my $format = "%*s%3s %3s %3s %3s %3s %3s %3s\n";
printf $format, $width, '', @headers;

for my $file (sort keys %file_data) {
  my $days = $file_data{$file};
  my @info = ('') x 7;
  for my $day (@$days) {
    my ($index, $val) = @$day;
    $info[$index] = $val;
  }
  printf $format, $width, $file, @info;
}

<强>输出

                    Sun Mon Tue Wed Thu Fri Sat
Report-20140521.csv: 20  22  22                
Report-20140530.csv: 23  23  23                
Report-20140606.csv: 24  24  20                
Report-20140613.csv: 25  24  21                
Report-20140621.csv: 21  21  21