5

假设我有一个这样的 csv 文件

a,b,c
1,"drivingme,mad",2

我想把它转换成 TSV

a<tab>b<tab>c
1<tab>drivingme,mad<tab>2

虽然我可以编写一些 Python 代码来做到这一点。我发现这很慢。即使行数达到数百万,是否有更好的 awk、sed 或 perl 方式非常快?

我需要这样做,因为我无法使用上述 csv 将 CSV 文件导入 SQLite 数据库,因为 SQLite 的 csv 导入功能有限。

4

5 回答 5

6

Text::CSV_XS(XS 是该模块的 C 版本,比原生 Perl Text::CSV 更快)是通常选择的工具。它

  • 轻松处理带引号(和包含逗号)的字段

  • 可用于阅读和写作

  • 可以在分隔符之间切换,这样您就可以使用 TAB 来创建写入器对象。

示例(无错误处理):

my $csv_in = Text::CSV_XS->new ({ binary => 1 });
my $csv_out = Text::CSV_XS->new ({ binary => 1, sep_char => "\t", eol => "\n" });
open my $fh_in, "<", "file_in.csv" or die "file_in.csv: $!";
open my $fh_out, ">", "file_out.csv" or die "file_out.csv: $!";

while (my $row = $csv_in->getline($fh_in)) {
    $csv_out->print ($fh_out, $row)
}
close $fh_in;
close $fh_out;
于 2013-06-18T06:39:29.183 回答
5

如果您有GNU awk(4.0 或更高版本),您可以使用以下单行代码:

$ awk '{$1=$1;gsub(/"/,"")}1' FPAT='([^,]+)|(\"[^\"]+\")' OFS='\t' file
a   b   c
1   drivingme,mad   2
于 2013-06-18T08:37:49.103 回答
3

不需要 Text::CSV。Text::ParseWords是标准 Perl 发行版的一部分。

#!/usr/bin/perl

use strict;
use warnings;
use Text::ParseWords;

while (<>) {
  print join "\t", parse_line(',', 0, $_);
}

将其称为 Unix 过滤器,如下所示:

$ ./csv2tsv < test.csv > test.tsv
于 2013-06-18T09:44:42.167 回答
2

对于大型 CSV 文件,我使用Parse::CSV。此外,您可以结合DBI + DBD::SQLite将已解析的行从 CSV 插入您的 SQLite 数据库

于 2013-06-18T06:39:59.860 回答
2

这可能对您有用(GNU sed):

sed -r ':a;s/(("[^"]*",)*"[^",]+),/\1\n/;ta;s/"//g;y/,\n/\t,/' file

用 's替换,'s within "' \ns。然后删除"'s 并将,'s and \n's 翻译成\t's and ,'s。

于 2013-06-19T09:06:22.297 回答