Python

Python

大容量の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サポートしていない場合は、リテラルタブを配置するか( - \tin 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

関連情報