我有许多大型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。
我有许多大型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。
Answers:
添加到名为的文件中csv2tab.sh
,并使其可执行
#!/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.sh
A C D,E,F G I K,L,M Z
$ ./csv2tab.sh < 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
csv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))
吗?也消除了循环。
python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'
。我怀疑那样-m
工作。
为了好玩,sed
。
sed -E 's/("([^"]*)")?,/\2\t/g' file
如果您sed
不支持-E
,请尝试-r
。如果您sed
不支持\t
文字标签,请尝试将文字标签(在许多shell中ctrl- v tab)或在Bash中使用$'...'
C样式的字符串(在这种情况下,反斜杠\2
需要加倍)。如果要保留引号,请使用\1
代替\2
(在这种情况下,内括号对无用,可以删除)。
这不会尝试处理双引号内的转义双引号。一些CSV方言通过将双引号(sic)加倍来支持此功能。
一个选项可能是perl的Text :: CSV模块,例如
perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
print join "\t", $csv->fields() if $csv->parse($_)
' somefile
展示
echo 'A,,C,"D,E,F","G",I,"K,L,M",Z' |
perl -MText::CSV -lne 'BEGIN { $csv = Text::CSV->new() }
print join "\t", $csv->fields() if $csv->parse($_)
'
A C D,E,F G I K,L,M Z
perl -lne '
my $re = qr/,(?=(?:[^"]*"[^"]*")*(?![^"]*"))/;
print join "\t", map { s/(?<!\\)"//gr =~ s/\\"/"/gr } split $re;
'
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
热核苍蝇拍解决方案必须使用libreoffice。而https://ask.libreoffice.org/en/question/19042/is-is-possible-to-convert-comma-separated-value-csv-to-tab-separated-value-tsv-via-headless-mode /表示这不可能,但这是错误的(或刚刚过时?),以下命令在我的5.3上有效:
loffice "-env:UserInstallation=file:///tmp/LibO_Conversion" --convert-to csv:"Text - txt - csv (StarCalc)":9,34,UTF8 --headless --outdir some/path --infilter='csv:44,34,UTF8' *.csv
env
可以跳过该参数,但是这样文档就不会出现在您最近的文档中。
我编写了一个开源的CSV到TSV转换器,可以处理上述转换。它的速度非常快,如果持续需要转换大型CSV文件,则可能值得一看。该工具是eBay的TSV实用程序工具包(此处为 csv2tsv文档)的一部分。默认选项足以说明所描述的输入:
$ csv2tsv file.csv > file.tsv
只是为了好玩,可以在Vim中执行正则表达式替换。这是一个潜在的四行解决方案,改编自:https : //stackoverflow.com/questions/33332871/remove-all-commas-between-quotes-with-a-vim-regex
引号被删除。
:%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
:%s/,/\t/g
:%s/_/,/g
:%s/"//g
要用某种方式编写解决方案的脚本,可以将上面的四行(无冒号)保存到文件中,例如to_tsv.vim
。打开每个CSV用于与编辑Vim的和source
所述to_tsv.vim
的上脚本Vim的命令行(改编自/programming/3374179/run-vim-script-from-vim-commandline/8806874#8806874):
:source /path/to/vim/filename/to_tsv.vim
这是使用jq
实用程序将CSV转换为TSV的示例:
$ jq -rn '@tsv "\(["A","","C","D,E,F","G","I","K,L,M","Z"])"'
A C D,E,F G I K,L,M Z
要么:
$ echo '["A","","C","D,E,F","G","I","K,L,M","Z"]' | jq -r @tsv
A C D,E,F G I K,L,M Z
但是,CSV格式必须格式正确,因此每个字符串都需要加引号。
来源:简单的TSV输出格式。
以下仅是对@tripleee答案的更正,以 使它像最后所有字段中的所有引号一样,删除最终字段中的所有引号。
为了显示正在纠正的内容,下面是一个三元组的答案,并对OP的示例数据进行了少许修改,并在最后的“ Z ”字段周围添加了引号。
echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' | sed -r -e 's/("([^"]*)")?,/\2\t/g'
A C D,E,F G I K,L,M "Z"
您会看到' Z '周围带有引号。这与内部字段的处理方式不同。例如,“ G ”上没有引号。
以下命令使用第二个替换来清除最后一列:
echo 'A,,C,"D,E,F","G",I,"K,L,M","Z"' | sed -r -e 's/("([^"]*)")?,/\2\t/g' \
-e 's/\t"([^"]*)"$/\t\1/'
A C D,E,F G I K,L,M Z
'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'
输入到此答案时,会"Z,A"
被错误地替换为Z A
,而不是正确的Z,A
。