多数の大きな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がインストールされています。
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
csvkit
(Python)を使用します。例:
$ csvformat -T in.csv > out.txt
正しいCSVとTSVの引用とエスケープを使用してストリーミングを行う
Aptや他のパッケージマネージャーにあります
楽しみのために、sed
。
sed -E 's/("([^"]*)")?,/\2\t/g' file
sed
が-E
をサポートしていない場合は、-r
で試してください。 sed
がリテラルタブの\t
をサポートしていない場合は、リテラルタブを配置してみてください(多くのシェルでは、 ctrl-vtab)またはBashでは、$'...'
Cスタイルの文字列を使用します(この場合、\2
のバックスラッシュは2重にする必要があります)。引用符を保持したい場合は、\1
の代わりに\2
を使用します(この場合、括弧の内側のペアは役に立たないため、削除できます)。
これは、二重引用符内のエスケープされた二重引用符を処理しようとするものではありません。一部のCSV方言は、引用符で囲まれた二重引用符(sic)を2倍にすることでこれをサポートしています。
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
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
csvtool
ユーティリティがある場合、またはインストールできる場合:
csvtool -t COMMA -u TAB cat in.csv > out.ctv
何らかの理由でcsvtool
にはmanページがありませんが、csvtool --help
は、数百行のドキュメントを印刷します。
熱核ハエたたき溶液は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
引数はスキップできますが、この方法では、ドキュメントは最近のドキュメントに表示されません。
mlr
の使用はほぼ簡単ですが、ヘッダーを無効にするには長いオプションが必要です。
mlr --c2t --implicit-csv-header --headerless-csv-output cat file.csv
出力:
A C D,E,F G I K,L,M Z
説明した変換を処理するオープンソースのCSVからTSVへのコンバーターを作成しました。非常に高速です。大きなCSVファイルを変換する必要がある場合は、一見の価値があります。ツールは eBayのTSVユーティリティツールキット の一部です(csv2tsvドキュメント ここ )。説明されている入力には、デフォルトのオプションで十分です。
$ csv2tsv file.csv > file.tsv
CSVをTSVに変換する際の考慮事項は、データ内のフィールドとレコードの区切り文字(カンマと改行)の処理です。 CSVはエスケープ構文を使用します。 cut
、awk
などのUnixツールで出力を使用することを目的とする場合は、出力にエスケープを含めないようにする必要があります。ここにリストされているほとんどのソリューションは、区切り文字がデータ内にある場合にCSVスタイルのエスケープを生成します。 csv2tsv
は、エスケープなしでTSVを生成するという点で他のソリューションとは異なります。詳細については、ドキュメントを参照してください。
特定のソリューションの機能を確認するには、データにカンマ、タブ、引用符、改行を含むCSVを変換します。例えば:
$ echo $'Line,Field1,Field2\n1,"Comma: |,|","Quote: |""|"\n"2","TAB: |\t|","Newline: |\n|"' | <conversion-script-or-command>
エスケープを生成するソリューションは、引用符、改行、またはタブを含むフィールドを二重引用符で囲みます。
楽しみのために、正規表現置換は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
ソリューションをいくらかスクリプト化するために、上記の4行(先頭のコロンを除く)をファイルに保存できます。 to_tsv.vim
。 Vimおよびsource
で編集するために各CSVを開き、上のto_tsv.vim
スクリプトVimコマンドライン( から適応) 8806874 ):
:source /path/to/vim/filename/to_tsv.vim
Perl
では、csvフィールドに"
または改行やタブが埋め込まれていないと仮定します。
Perl -pe 's{"(.*?)"|,}{$1//"\t"}ge'
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出力形式 。
以下は、 @ 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