我有许多大型 CSV 文件,希望它们采用 TSV(制表符分隔格式)。复杂的是 CSV 文件的字段中有逗号,例如:
A,,C,"D,E,F","G",I,"K,L,M",Z
预期输出:
A C D,E,F G I K,L,M Z
(其中之间的空格是“硬”选项卡)
我已在此服务器上安装了 Perl、Python 和 coreutils。
答案1
Python
添加到名为 的文件csv2tab
,并使其可执行
touch csv2tab && chmod u+x csv2tab
添加到它
#!/usr/bin/env python
import csv, sys
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))
试运行
$ echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' | ./csv2tab
A C D,E,F G I K,L,M Z
$ ./csv2tab < data.csv > data.tsv && head data.tsv
1A C D,E,F G I K,L,M Z
2A C D,E,F G I K,L,M Z
3A C D,E,F G I K,L,M Z
答案2
使用csvkit
(Python),例如:
$ csvformat -T in.csv > out.txt
是否进行流式传输,并使用正确的 CSV 和 TSV 引用和转义
它位于 apt 和其他包管理器中
答案3
为了娱乐,sed
。
sed -E 's/("([^"]*)")?,/\2\t/g' file
如果您sed
不支持-E
,请尝试使用-r
。如果您sed
不支持\t
文字制表符,请尝试放置文字制表符(在许多 shell 中为ctrl- v tab)或在 Bash 中使用C 样式字符串(在这种情况下,需要加倍$'...'
反斜杠)。\2
如果你想保留引号,请使用\1
not \2
(在这种情况下,内部一对括号没有用,可以删除)。
如果您sed
不支持-E
或-r
,请尝试
sed 's/\("\([^"]*\)"\)\?,/\2\t/g' file
\t
如果不支持,可能会再次使用上面建议的调整。
为了获得更多乐趣,这里有与 Bash“here-string”语法相同的内容,只是为了演示它的样子。请注意我们想要接收的文字反斜杠sed
现在是如何加倍的:
sed $'s/\\("\\([^"]*\\)"\\)\\?,/\\2\t/g' file
这不会尝试处理双引号内的转义双引号;某些 CSV 方言通过加倍双引号 (sic) 来支持这一点。
答案4
珀尔
perl -lne '
my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
print join "\t", map { s/(?<!\\)"//gr =~ s/\\"/"/gr } split $re;
'
awk
awk -v Q=\" -v FPAT="([^,]*)|(\"[^\"]+\")" -v OFS="\t" '{
for (i=1; i<=NF; ++i)
if ( substr($i, 1, 1) == Q )
$i = substr($i, 2, length($i) - 2)
print $1, $2, $3, $4, $5, $6, $7, $8
}'
结果:
A C D,E,F G I K,L,M Z