CSVをTSVに変換する


27

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


node.jsまたはperlでこれを行います。
ペテルはモニカを

1
引用符で囲まれていないコンマをタブに置き換えます
...-cricket_007

はい、この質問に5分以上かかった場合。しかし、投票者は回答者を喜んでサポートします。私が言いたいことは、一般的なsed / awkの事柄はおそらくそれにはふさわしくないということです(少なくとも一般的に使用される使用法では)。
ペテルはモニカを

6
あなたの例が実際のデータを表しているかどうかはわかりませんが、それらが実際のテキスト文字列になる場合は、文字列にタブが含まれるケースを処理する必要があることを忘れないでください...
AC

3
もう1つの注意すべき点は、CSVが非常に緩やかに定義された形式であり、実際の標準がないことです(RFCがありますが、事実から数年後に書かれました)。言語提供のCSVパーサーを使用するコードを記述した後、入力データがcsv形式の壊れたバリアントであることがわかったため、カスタムパーサーで書き換える必要がありました。
プラグウォッシュ

回答:


37

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

5
バグの可能性:この回答は内部タブをエスケープしません。
モルゲン

4
@モルゲンcsv.writer(sys.stdout, dialect='excel-tab').writerows(csv.reader(sys.stdin))?ループも排除します。
ムル

1
@chx try python -c 'import csv,sys; csv.writer(sys.stdout, dialect="excel-tab").writerows(csv.reader(sys.stdin))'。私-mはそのようにはたらかないと思う。
ムル

18

お楽しみにsed

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

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

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


1
私はこれを達成するために約100種類のsedスクリプトを試しましたが、すべての試みは失敗しました。これはすごい。
ジョージヴァシリウ


13

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

1
フィールドにタブが含まれている場合は正しくありません
ニールマクギガン

6

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

+1 Perlバージョンは魅力のように機能します
ATorras

4

熱核ハエのたたきソリューションでは、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引数を省略することができたが、この方法は、文書は、あなたの最近の文書には表示されません。


2
真の熱核ハエは、LibreOfficeのUNO APIを介してそれを行うためのJavaユーティリティを書くことになると思います:)。
ポン

3

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

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

なんらかの理由でcsvtoolマニュアルページはありませんがcsvtool --help、数百行のドキュメントを印刷することに注意してください。


3

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

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

出力:

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

3

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

$ csv2tsv file.csv > file.tsv

2

Vim

楽しみのために、Vimで正規表現の置換を実行できます。以下から適応される潜在的な4行のソリューションがあります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.vim。で編集するための各CSVを開くのVimとのスクリプトVimの(から適合コマンドライン/programming/3374179/run-vim-script-from-vim-commandline/8806874#8806874)。 sourceto_tsv.vim

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

1

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出力形式



0

以下は@ tripleeeからの回答に対する単なる修正 であり、他のすべてのフィールドと同様に、最終フィールドから引用符を取り除きます。

何が修正されているかを示すために、以下にトリプリーの回答と、最後の「Z」フィールドの前後に引用符を追加したOPのサンプルデータへのわずかな変更を示します。

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

1
入力データ'A,,C,"D,E,F","G",I,"K,L,M","Z,A"'がこの回答に入力される"Z,A"Z A、はでなくで誤って置き換えられますZ,A
agc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.