web-dev-qa-db-ja.com

CSVからTSVへの変換

多数の大きな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がインストールされています。

28
DarkHeart

Python

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
41
cricket_007

csvkit (Python)を使用します。例:

$ csvformat -T in.csv > out.txt

正しいCSVとTSVの引用とエスケープを使用してストリーミングを行う

Aptや他のパッケージマネージャーにあります

19
Neil McGuigan

楽しみのために、sed

sed -E 's/("([^"]*)")?,/\2\t/g' file

sed-Eをサポートしていない場合は、-rで試してください。 sedがリテラルタブの\tをサポートしていない場合は、リテラルタブを配置してみてください(多くのシェルでは、 ctrl-vtab)またはBashでは、$'...' Cスタイルの文字列を使用します(この場合、\2のバックスラッシュは2重にする必要があります)。引用符を保持したい場合は、\1の代わりに\2を使用します(この場合、括弧の内側のペアは役に立たないため、削除できます)。

これは、二重引用符内のエスケープされた二重引用符を処理しようとするものではありません。一部のCSV方言は、引用符で囲まれた二重引用符(sic)を2倍にすることでこれをサポートしています。

19
tripleee

1つのオプションは、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
13
steeldriver

Perl

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
7
user218374

csvtoolユーティリティがある場合、またはインストールできる場合:

csvtool -t COMMA -u TAB cat in.csv > out.ctv

何らかの理由でcsvtoolにはmanページがありませんが、csvtool --helpは、数百行のドキュメントを印刷します。

5
Keith Thompson

熱核ハエたたき溶液は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引数はスキップできますが、この方法では、ドキュメントは最近のドキュメントに表示されません。

5
chx

mlr の使用はほぼ簡単ですが、ヘッダーを無効にするには長いオプションが必要です。

mlr --c2t --implicit-csv-header --headerless-csv-output cat file.csv 

出力:

A       C   D,E,F   G   I   K,L,M   Z
4
agc

説明した変換を処理するオープンソースのCSVからTSVへのコンバーターを作成しました。非常に高速です。大きなCSVファイルを変換する必要がある場合は、一見の価値があります。ツールは eBayのTSVユーティリティツールキット の一部です(csv2tsvドキュメント ここ )。説明されている入力には、デフォルトのオプションで十分です。

$ csv2tsv file.csv > file.tsv

CSVをTSVに変換する際の考慮事項は、データ内のフィールドとレコードの区切り文字(カンマと改行)の処理です。 CSVはエスケープ構文を使用します。 cutawkなどのUnixツールで出力を使用することを目的とする場合は、出力にエスケープを含めないようにする必要があります。ここにリストされているほとんどのソリューションは、区切り文字がデータ内にある場合にCSVスタイルのエスケープを生成します。 csv2tsvは、エスケープなしでTSVを生成するという点で他のソリューションとは異なります。詳細については、ドキュメントを参照してください。

特定のソリューションの機能を確認するには、データにカンマ、タブ、引用符、改行を含むCSVを変換します。例えば:

$ echo $'Line,Field1,Field2\n1,"Comma: |,|","Quote: |""|"\n"2","TAB: |\t|","Newline: |\n|"' | <conversion-script-or-command>

エスケープを生成するソリューションは、引用符、改行、またはタブを含むフィールドを二重引用符で囲みます。

4
JonDeg

Vim

楽しみのために、正規表現置換はVimで実行できます。 https://stackoverflow.com/questions/33332871/remove-all-commas-between-quotes-with-a-vim-regex

  1. 引用符の間のコンマは、最初にアンダースコア(またはその他の不在文字)に変更されます。
  2. 他のすべてのコンマはタブで置き換えられます、
  3. 引用符内のアンダースコアはカンマに復元されます。
  4. 引用符が削除されます。

    :%s/".\{-}"/\=substitute(submatch(0), ',', '_' , 'g')/g
    :%s/,/\t/g
    :%s/_/,/g
    :%s/"//g
    

ソリューションをいくらかスクリプト化するために、上記の4行(先頭のコロンを除く)をファイルに保存できます。 to_tsv.vimVimおよびsourceで編集するために各CSVを開き、上のto_tsv.vimスクリプトVimコマンドライン( から適応) 8806874 ):

    :source /path/to/vim/filename/to_tsv.vim
2
jubilatious1

Perlでは、csvフィールドに"または改行やタブが埋め込まれていないと仮定します。

Perl -pe 's{"(.*?)"|,}{$1//"\t"}ge'
1

jq utility を使用して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出力形式

1
kenorb

以下は、 @ tripleee からの回答を単に修正して、引用符を他のすべてのフィールドと同じように、最終フィールド。

何が修正されているかを示すために、以下はtripleeeの回答と、最後の '[〜#〜] 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 [〜#〜]」には引用符がありません。

次のコマンドは、2番目の置換を使用して最後の列を消去します。

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
0
Fonnae