从一个csv文件中的数据创建多个csv文件
系统:OSX或Linux
我想在工作中自动化我的工作流程,每周我都会收到一个Excel文件,然后把它转换成CSV格式。
这里有个例子:
,,L1,,,L2,,,L3,,,L4,,,L5,,,L6,,,L7,,,L8,,,L9,,,L10,,,L11,
Title,r/t,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst,neede d,actual,Inst,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst,needed,actual,Inst
EXAMPLEfoo,60,6,6,6,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
EXAMPLEbar,30,6,6,12,6,7,14,6,6,12,6,6,12,6,8,16,6,7,14,6,7.5,15,6,6,12,6,8,16,6,0,0,6,7,14
EXAMPLE1,60,3,3,3,3,5,5,3,4,4,3,3,3,3,6,6,3,4,4,3,3,3,3,4,4,3,8,8,3,0,0,3,4,4
EXAMPLE2,120,6,6,3,0,0,0,6,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
EXAMPLE3,60,6,6,6,6,8,8,6,6,6,6,6,6,0,0,0,0,0,0,6,8,8,6,6,6,0,0,0,0,0,0,0,10,10
EXAMPLE4,30,6,6,12,6,7,14,6,6,12,6,6,12,3,5.5,11,6,7.5,15,6,6,12,6,0,0,6,9,18,6,0,0,6,6.5,13
为了让你更好地理解Excel里的样子,这里有个截图:

我需要做的是为第一行中的每个实例创建多个CSV文件,也就是L1、L2、L3、L4……
而每个CSV文件里需要包含标题、r/t和需要的内容。
比如,L1的输出示例可能是:
EXAMPLEfoo,60,6
EXAMPLEbar,30,6
EXAMPLE1,60,3
EXAMPLE2,120,6
EXAMPLE3,60,6
EXAMPLE4,30,6
对于L2来说:
EXAMPLEfoo,60,0
EXAMPLEbar,30,6
EXAMPLE1,60,3
EXAMPLE2,120,0
EXAMPLE3,60,6
EXAMPLE4,30,6
依此类推。
我尝试过用sed和awk来处理这个问题,还在谷歌上查找过,但没有找到真正能解决这个问题的方法。
我想perl可能特别适合这个任务,或者也许python也可以,所以我很乐意接受大家的建议。
所以,有什么建议吗?
提前谢谢大家。
6 个回答
2
这段代码是用来处理一些特定的任务的。它可能涉及到一些数据的输入、处理和输出。具体来说,代码块中的内容会按照一定的逻辑进行执行,可能会有条件判断、循环等结构,帮助程序完成它的目标。
如果你对代码的具体功能有疑问,可以尝试逐行分析,看看每一行代码在做什么,或者查找相关的资料来帮助理解。记住,编程就像解谜,慢慢来,总能找到答案!
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new;
sub parse_line {
$csv->parse(shift) or die $!;
return $csv->fields;
}
my @metadata;
my @files = parse_line(scalar <>);
my @header = parse_line(scalar <>); # Ignore.
for my $i (0 .. $#files){
next unless length $files[$i];
open(my $h, '>', "$files[$i].csv") or die $!;
push @metadata, {column => $i, handle => $h};
}
while (my $line = <>){
my @fields = parse_line($line);
for my $m (@metadata){
$csv->print($m->{handle}, [ @fields[0, 1, $m->{column}] ]);
print {$m->{handle}} "\n";
}
}
3
Perl“一行代码”
perl -MText::CSV_XS -e'$c=Text::CSV_XS->new({binary=>1,eol=>"\n"});%a=map{$i++;/^L\d+$/?($_=>$i):()}@{$c->getline(*ARGV)};open$b{$_},">$_"for keys%a;while($f=$c->getline(*ARGV)){$c->print($b{$_},[@$f[0,1,$a{$_}]])for keys%a}'
对于那些在阅读上有问题的:
$ echo '$c=Te...' | perltidy
$c = Text::CSV_XS->new( { binary => 1, eol => "\n" } );
%a = map { $i++; /^L\d+$/ ? ( $_ => $i ) : () } @{ $c->getline(*ARGV) };
open $b{$_}, ">$_" for keys %a;
while ( $f = $c->getline(*ARGV) ) {
$c->print( $b{$_}, [ @$f[ 0, 1, $a{$_} ] ] )
for keys %a;
}
2
仅使用 AWK:
awk -F, -vOFS=, -vc=1 '
NR == 1 {
for (i=1; i<NF; i++) {
if ($i != "") {
g[c]=i;
f[c++]=$i
}
}
}
NR>2 {
for (i=1; i < c; i++) {
print $1,$2, $g[i] > "output_"f[i]".csv"
}
}' data.csv
作为一行代码:
awk -F, -vOFS=, -vc=1 'NR == 1 {for (i=1; i<NF; i++) {if ($i != "") {g[c]=i; f[c++]=$i}}} NR>2 { for (i=1; i < c; i++) {print $1,$2, $g[i] > "file_"f[i]".csv" }}' data.csv
示例输出:
$ cat file_L1.csv
EXAMPLEfoo,60,6
EXAMPLEbar,30,6
EXAMPLE1,60,3
EXAMPLE2,120,6
EXAMPLE3,60,6
EXAMPLE4,30,6
$ cat file_L2.csv
EXAMPLEfoo,60,0
EXAMPLEbar,30,6
EXAMPLE1,60,3
EXAMPLE2,120,0
EXAMPLE3,60,6
EXAMPLE4,30,6
$ cat file_L11.csv
EXAMPLEfoo,60,0
EXAMPLEbar,30,6
EXAMPLE1,60,3
EXAMPLE2,120,0
EXAMPLE3,60,0
EXAMPLE4,30,6