如何将文件合并为一个CSV文件?

时间:2009-07-13 15:07:19

标签: perl csv

如果我有一个文件FOO_1.txt包含:

FOOA

FOOB

FOOC

FOOD

...

以及许多其他文件FOO_files.txt。每个都包含:

... 1110000000

一行包含01作为FOO1值的数量fooafoob,...)

现在我想将它们合并到一个文件FOO_RES.csv,该文件将具有以下格式:

FOOA,1,0,0,0,0,0,0...

FOOB,1,0,0,0,0,0,0...

FOOC,1,0,0,0,1,0,0...

FOOD,0,0,0,0,0,0,0...

...

什么是简单&优雅的方式来进行 (使用哈希和数组 - > $ hash {$ key} = \ @data)?

非常感谢您的帮助!

Yohad

5 个答案:

答案 0 :(得分:3)

如果您无法清楚地描述您的数据和所需的结果,则无法对其进行编码 - 采用简单的项目是开始使用新语言的好方法。< / p>

请允许我提供一种简单的方法,您可以用它来制作任何语言的代码,无论您是否知道。此方法仅适用于小型项目。您需要提前计划更大的项目。

如何编写程序:

  1. 打开文本编辑器并记下您拥有的数据。让每一行都成为评论
  2. 描述您想要的结果。
  3. 开始介绍将数据更改为所需表单所需的步骤。
  4. 数字1&amp; 2完成:

    #!/usr/bin perl
    use strict;
    use warnings;
    
    # Read data from multiple files and combine it into one file.
    # Source files:
    #    Field definitions: has a list of field names, one per line.
    #    Data files:  
    #      * Each data file has a string of digits.
    #      * There is a one-to-one relationship between the digits in the data file and the fields in the field defs file.
    # 
    # Results File:
    # * The results file is a CSV file.
    # * Each field will have one row in the CSV file.
    # * The first column will contain the name of the field represented by the row.
    # * Subsequent values in the row will be derived from the data files.
    # * The order of subsequent fields will be based on the order files are read.
    # * However, each column (2-X) must represent the data from one data file.
    

    既然你知道你拥有什么,你需要去哪里,你可以充实程序需要做的事情来实现目标 - 这是第3步:

    你知道你需要有字段列表,所以先得到它:

    # Get a list of fields.
    #   Read the field definitions file into an array.
    

    由于最容易以面向行的方式编写CSV,因此您需要在生成每一行之前处理所有文件。所以你需要一个地方来存储数据。

    # Create a variable to store the data structure.
    

    现在我们读取数据文件:

    # Get a list of data files to parse
    # Iterate over list
    
    # For each data file:
    #    Read the string of digits.
    #    Assign each digit to its field.
    #    Store data for later use.
    

    我们已经将所有数据都存储在内存中,现在写出输出:

    # Write the CSV file.
    # Open a file handle.
    
    # Iterate over list of fields
    # For each field
    #   Get field name and list of values.
    #   Create a string - comma separated string with field name and values  
    #   Write string to file handle
    
    # close file handle.
    

    现在您可以开始将注释转换为代码。每条评论可以包含1到100行代码。你可能会发现你需要做的事情非常复杂,你现在不想接受它。创建一个虚拟子例程来处理复杂的任务,并在完成其他所有操作之前忽略它。现在你可以自己解决那个复杂棘手的子问题。

    由于您刚刚学习Perl,因此您需要访问文档以了解如何执行您编写的注释所代表的每个子任务。这类工作的最佳资源是the list of functions by category in perlfuncPerl syntax guide也会派上用场。由于您需要使用复杂的数据结构,因此您还需要阅读Data Structures Cookbook

    您可能想知道您应该知道哪些perldoc页面应该针对给定问题阅读。一篇名为How to RTFM的Perlmonks文章提供了对文档以及如何使用它的精彩介绍。

    最棒的是,如果你遇到问题,你可以在寻求帮助时分享一些代码。

答案 1 :(得分:1)

如果我理解正确,您的第一个文件是您的密钥订单文件,其余文件每个按键包含一个字节,顺序相同。您需要这些键的复合文件,其中每个数据字节都列在一起。

在这种情况下,您应该同时打开所有文件。从密钥订单文件中读取一个密钥,从每个数据文件中读取一个字节。在读到最终文件时输出所有内容。重复每个键。

答案 2 :(得分:1)

您的规格不明确。您不能拥有“很多其他文件”名为 FOO_files.txt,因为它只有一个名称。所以我将把它作为带有数据的文件+文件列表模式。在这种情况下,有一些名为FOO*.txt的文件,每个文件包含“[01] + \ n”。

因此,我们的想法是处理文件列表文件中的所有文件,并将它们全部插入到以逗号分隔的结果文件FOO_RES.csv中。

use strict;
use warnings;
use English qw<$OS_ERROR>;
use IO::Handle;

open my $foos, '<', 'FOO_1.txt'
    or die "I'm dead: $OS_ERROR";
@ARGV = sort map { chomp; "$_.txt" } <$foos>;
$foos->close;

open my $foo_csv, '>', 'FOO_RES.csv'
    or die "I'm dead: $OS_ERROR";

while ( my $line = <> ) { 
    my ( $foo_name ) = ( $ARGV =~ /(.*)\.txt$/ );
    $foo_csv->print( join( ',', $foo_name, split //, $line ), "\n" );
}

$foo_csv->close;

答案 3 :(得分:1)

看起来你有很多foo_files,其中包含1行,如:

1110000000

哪个代表

fooa=1
foob=1
fooc=1
food=0
fooe=0
foof=0
foog=0
fooh=0
fooi=0
fooj=0

看起来你的foo_res只是这些值的总和?在这种情况下,您不需要数组哈希,只需要哈希。

my @foo_files = (); #NOT SURE HOW YOU POPULATE THIS ONE
my @foo_keys = qw(a b c d e f g h i j);
my %foo_hash = map{ ( $_, 0 ) } @foo_keys; # initialize hash
foreach my $foo_file ( @foo_files ) {
  open( my $FOO, "<", $foo_file) || die "Cannot open $foo_file\n";
  my $line = <$FOO>;
  close( $FOO );
  chomp($line);
  my @foo_values = split(//, $line);
  foreach my $indx ( 0 .. $#foo_keys ) {
    last if ( ! $foo_values[ $indx ] ); # or some kind of error checking if the input file doesn't have all the values
    $foo_hash{ $foo_keys[$indx] } += $foo_values[ $indx ];
  }
}

很难理解你的要求,但也许这有帮助吗?

答案 4 :(得分:0)

你真的不需要使用哈希。 我的Perl有点生疏,所以语法可能有点,但基本上这样做:

open KEYFILE , "foo_1.txt" or die "cannot open foo_1 for writing";
open VALFILE , "foo_files.txt" or die "cannot open foo_files for writing";
open OUTFILE , ">foo_out.txt"or die "cannot open foo_out for writing";

my %output;
while (<KEYFILE>) {
    my $key = $_;
    my $val = <VALFILE>;
    my $arrVal = split(//,$val);

    $output{$key} = $arrVal;
    print OUTFILE $key."," . join(",", $arrVal)
}

编辑:语法检查确定

Sinan的评论: @Byron,你的第一句话说OP不需要哈希但你的代码有%output这似乎没有任何意义。作为参考,以下是做同样事情的不那么冗长的方式。

#!/usr/bin/perl

use strict;
use warnings;

use autodie qw(:file :io);

open my $KEYFILE, '<', "foo_1.txt";
open my $VALFILE, '<', "foo_files.txt";
open my $OUTFILE, '>', "foo_out.txt";

while (my $key = <$KEYFILE>) {
    chomp $key;
    print $OUTFILE join(q{,}, $key, split //, <$VALFILE> ), "\n";
}
__END__