web-dev-qa-db-ja.com

CSVファイルの処理-引用符を削除し、カンマ区切り文字をタブに置き換えます

シェルコマンドで区切られたファイルを変換する必要があります。受信した入力ファイルには2つのバリエーションがあり、1つは二重引用符があり、もう1つは引用符がありません。両方のファイルに区切り文字としてコンマがあります。要件は、ファイルに二重引用符がある場合はコンマをTABで置き換え、引用符を削除することです。それ以外の場合は、単にコンマを置き換えます。変換中に無視する必要があるコンマがフィールドにも含まれている場合、ファイルは引用符付きで送信されます。 単一のコマンドは、RHEL 6.x環境のAwk 3.xで有効でなければなりません。

例えば。二重引用符付きのファイル1:

"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"

変換後はタブで区切る必要があります:

Jhon   Carpenter   CA,TX,NJ 
Mike   Painter     WA,GA,MI 

例えば。二重引用符のないファイル2:

EMP1,123456,CA 
EMP2,456789,TX 

変換後はタブで区切る必要があります:

EMP1 123456   CA 
EMP2   456789   TX
3

この短いsedスクリプトは、両方のタイプのファイル(または1番目と2番目のタイプの行が混在するファイル)を処理できます。

sed '/"/!s/,/\t/g;s/","/\t/g; s/"//g'

ループしない式をグループ化しないため、スクリプトよりもはるかに高速です。

GNU sedなので、\tは機能しますが、それ以外の場合は代わりにリテラルTABを使用します。

1
Philippos

csvkit を使用:

$ csvformat -T file1.csv
Jhon    Carpenter       CA,TX,NJ
Mike    Painter WA,GA,MI

$ csvformat -T file2.csv
EMP1    123456  CA
EMP2    456789  TX

file1.csvの出力は少し外れているように見えますが、それはタブが正しく並んでいないためです。すべての列の間にタブがあります。

CSVKitは、さまざまなCSV関連のシェルユーティリティのPythonベースのツールボックスです。これは適切なCSV解析を行い、CSVファイルのクエリ、フォーマット、変換に使用できます。

たとえば、最初のファイルに適切なヘッダーがある場合、これをJSONに変換するのは簡単です。

$ csvjson file1.csv
[{"First": "Jhon", "Last": "Carpenter", "Stuff": "CA,TX,NJ"}, {"First": "Mike", "Last": "Painter", "Stuff": "WA,GA,MI"}]
3
Kusalananda

いくつかのアプローチ:

のために file1(二重引用符付き):

-awkアプローチ:

awk -F'"' '{ r=""; for(i=1;i<NF;i++) 
     if ($i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i; print r }' OFS='\t' file1

-sedアプローチ:

sed 's/","/\t/g; s/"//g;' file1

出力(両方のアプローチ):

Jhon    Carpenter   CA,TX,NJ
Mike    Painter WA,GA,MI

----------

のために file2(二重引用符なし)-trコマンドを適用するだけで十分です:

tr ',' '\t' <file2

出力:

EMP1    123456  CA
EMP2    456789  TX

----------

条件「sameコマンドで両方のファイルタイプで十分なはずです」の統一されたアプローチ:

awk -v quoted=$(grep -cm1 '"' file1) 'BEGIN{ FS=(quoted)? "\"" : ","; }
     { r=""; for(i=1;i<=NF;i++) if(!quoted || $i~/^[[:alnum:]]/) r=(r!="")? r OFS $i : $i; 
             print r }' OFS='\t' file1
2
RomanPerekhrest

さて、この解決策はKusalanandaの回答ほどエレガントではありませんし、あなたが望むほど速くはないでしょうが、それはうまくいくはずです。

#!/usr/bin/env bash

for file; do

  while read -r line; do

    if <<< "${line}" grep -F -e '"' > '/dev/null' 2>&1; then
      <<< "${line}" \
      grep -P -o -e '(?<=")([^,].*?)(?=")' |
      tr $'\n' $'\t' | rev | cut -c 2- | rev
    else
      <<< "${line}" \
      tr ',' $'\t'
    fi

  done < "${file}"

done

例:

$ cat file1
"Jhon","Carpenter","CA,TX,NJ"
"Mike","Painter","WA,GA,MI"

$ cat file2
EMP1,123456,CA
EMP2,456789,TX

$ script.sh file1 file2
Jhon    Carpenter   CA,TX,NJ
Mike    Painter WA,GA,MI
EMP1    123456  CA
EMP2    456789  TX
0
nxnev

CSVデータには適切なCSVパーサーが必要です。クサラナンダの答えが好きです。 csvモジュールに付属するRubyのような言語を使用することもできます。

Ruby -rcsv -e '
  out = CSV.new($stdout, {:col_sep => "\t"})
  CSV.foreach(ARGV.shift) {|row| out << row} 
' file1.csv
0
glenn jackman