大容量の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
in Many Shells )BashでCスタイル文字列を使用してみてください(この場合はバックスラッシュを2倍にする必要があります)。引用符を保持するには not を使用します (この場合、内部括弧のペアは役に立たないので削除できます)。ctrlv tab$'...'
\2
\1
\2
または をsed
サポートしていない場合はお試しください。-E
-r
sed 's/\("\([^"]*\)"\)\?,/\2\t/g' file
\t
サポートされていない場合は、上記の調整を再利用できます。
もっと楽しく見るために、Bashの「here-string」構文と同じ構文を見てみましょう。sed
受け取りたいリテラルバックスラッシュがどのように倍増したかを確認してください。
sed $'s/\\("\\([^"]*\\)"\\)\\?,/\\2\t/g' file
これは、二重引用符内でエスケープされた二重引用符を処理しようとしません。一部のCSV方言は二重引用符を2倍にし、それをサポートします(sic)。
答え4
真珠
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