我确信我已经完成了这项工作,并且有一些我忘记的东西,但是如何在特定列上对CSV文件进行排序?我对有或没有第三方Perl模块的答案感兴趣。主要方法没有,因为我不总是有权安装额外的模块。根据某一列对CSV进行排序?
示例数据:
name,25,female name,24,male name,27,female name,21,male
所需的2号数字列排序后,最终结果是:
name,21,male name,24,male name,25,female name,27,female
我确信我已经完成了这项工作,并且有一些我忘记的东西,但是如何在特定列上对CSV文件进行排序?我对有或没有第三方Perl模块的答案感兴趣。主要方法没有,因为我不总是有权安装额外的模块。根据某一列对CSV进行排序?
示例数据:
name,25,female name,24,male name,27,female name,21,male
所需的2号数字列排序后,最终结果是:
name,21,male name,24,male name,25,female name,27,female
当你提供你自己的比较代码,你可以排序任何东西。只需用正则表达式提取所需的元素,或者在这种情况下可能是分割,然后再比较。如果您有很多元素,我会将数据解析为列表列表,然后比较代码可以在不解析的情况下访问它。这将消除解析同一行,因为它与其他行进行比较。
由于CSV是一个相当复杂的格式,最好使用为我们做的工作。
下面是使用Text::CSV模块的示例:
#!/usr/bin/env perl
use strict;
use warnings;
use constant AGE => 1;
use Text::CSV;
my $csv = Text::CSV->new();
my @rows;
while (my $row_ref = $csv->getline(\*DATA)) {
push @rows, $row_ref;
}
@rows = sort { $a->[AGE] <=> $b->[AGE] } @rows;
for my $row_ref (@rows) {
$csv->combine(@$row_ref);
print $csv->string(), "\n";
}
__DATA__
name,25,female
name,24,male
name,27,female
name,21,male
还有DBD::CSV:
#!/usr/bin/perl
use strict; use warnings;
use DBI;
my $dbh = DBI->connect('dbi:CSV:', undef, undef, {
RaiseError => 1,
f_ext => '.csv',
csv_tables => { test => { col_names => [qw' name age sex '] } },
});
my $sth = $dbh->prepare(q{
SELECT name, age, sex FROM test ORDER BY age
});
$sth->execute;
while (my @row = $sth->fetchrow_array) {
print join(',' => @row), "\n";
}
$sth->finish;
$dbh->disconnect;
输出:
name,21,male name,24,male name,25,female name,27,female
我会做这样的事情:
#!/usr/bin/perl
use warnings;
use strict;
my @rows = map { chomp; [split /[,\s]+/, $_] } <DATA>; #read each row into an array
my @sorted = sort { $a->[1] <=> $b->[1] } @rows; # sort the rows (numerically) by second column
for (@sorted) {
print join(', ', @$_) . "\n"; # print them out as CSV
}
__DATA__
name,25,female
name,24,male
name,27,female
name,21,male
好的,只要你的姓名中没有John Doe,Esq.'。 – reinierpost 2010-11-19 10:20:32
我们有像CSV文件一样的CSV解析模块是有原因的。在一般情况下,以逗号分割就不够了。 – 2010-11-19 11:13:15
本着永远有另一种方式来做到这一点的精神,请记住,简单的旧的GNU排序可能就足够了。
$ sort -t, -k2 -n unsorted.txt
name,21,male
name,24,male
name,25,female
name,27,female
当命令行参数是:
-t, # use comma as the record separator
-k2 # sort on the second key (record) in the line
-n # sort using numerical comparison (like using <=> instead of cmp in perl)
如果你想有一个Perl的解决方案,将它包装在QX();-)
楼主问没有第三方模块(我认为它不代表CPAN)。虽然这种限制会严重限制您编写优秀的现代Perl代码的能力,但在这种情况下,可以使用(核心)Text :: ParseWords模块代替(非核心)Text :: CSV。因此,我们从Alan的例子中大量借鉴,我们得到:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::ParseWords;
my @rows;
while (<DATA>) {
push @rows, [ parse_line(',', 0, $_) ];
}
@rows = sort { $a->[1] <=> $b->[1] } @rows;
foreach (@rows) {
print join ',', @$_;
}
__DATA__
name,25,female
name,24,male
name,27,female
name,21,male
很好的答案。运行'split /,/'真的很诱人,但对于Micro $ oft风格的CSV文件来说,这还不够好。我认为这对于Unix冒号分隔的foocap文件来说还不够好。 – tchrist 2010-11-19 02:55:41
tchrist:对。很高兴收到你的评论,先生!谢谢。 :-) – 2010-11-19 03:12:13
Perl新手。这是一个内存中的解决方案吗?有没有简单的方法可以用大文件做同样的事情?谢谢 – Gevorg 2013-06-04 17:55:30