他のvarchar配列を切り捨てずにCSVでint配列列を切り捨てる

他のvarchar配列を切り捨てずにCSVでint配列列を切り捨てる

次のCSVがあります。

details.csv

1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,"{1,2,3}",{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,"{4,5,6,7,8,9}",{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{1,9}","{NORMAL,BOOKING}",1,2,

ここで、列 15 は空で、列 12 は単一値の場合、引用符はありません({予約})と複数の値がある場合は引用符(「{予約、正常}」)。

ここでint配列で固定サイズのない11個の列を削除したいと思います。だから出力は次のようになります

mod_details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

だから私は次のことを試みます:

sed 's/,"{.*}"//' details.csv > mod_details.csv

しかし、問題は私が得た結果です

mod_details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,1,2,

また、引用符があるため、複数の値を持つ列の12値も削除されます。どんな助けでも大変感謝します。よろしくお願いします。

答え1

実際には特に難しくありません。以下より具体的なパターンを使用する必要があります{.*}

sed 's/"{\([0-9],\)\+[0-9]}",//' details.csv

答え2

答えを見つけるステップとして、次のシェル機能が役に立ちます。私はコマンドラインで素晴らしい「きれいな」レイアウトでCSVを見るために書いています。

それに注意を払う削除引用符で囲まれたカンマと引用符で囲まれた改行(および引用符で囲まれた二重引用符)はおそらく望むものではありませんが、列をすばやく確認して正しく並べ替えるのに役立ちます。

excel() {
    sed -E -e ':t' -e '/^[^"]*("[^"]*"[^"]*)*$/!{N;s/\n//;bt' -e'}' "$@" |
      awk -F\" -v OFS= 'NF>1 {for (i=2;i<=NF;i+=2) gsub(/,/, "", $i)} 1' |
      sed 's/,/,"/g' | column -ts, | tr -d '"' | less -S
}

答え3

使用csvkit:

$ csvcut -C 11 details.csv
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

答え4

各行を"区切り記号として配列に分割する方が簡単な方法です。これにより、int配列は配列の要素1になり、それを空の文字列に設定でき、次の要素(要素2)に末尾に追加のコンマが追加されるため、次から始まる文字列を抽出できます。 2番目のキャラクターが始まります。どういう{NORMAL,BOOKING}わけか、そのセクションに二重引用符を返す操作を処理する必要があります。分割線を"区切り文字として使用すると、行にフィールド3があるため、この部分も処理されます。別の行の場合は引用符がなくなったため、アイテムの配列にはインデックス2より前のアイテムのみが含まれます。インデックス#3があればそれを参照する必要があることを知っています。

Perlの次の1行は、上記で説明したものとまったく同じことを行います。

$ perl -F'"' -lane '$F[1]="";$F[2]=substr($F[2],1);$F[3]= "\"" . $F[3] . "\"" if $F[3];print @F' inpu>
1,2,3,4,5,2015-07-30 23:17:12,2015-07-30 23:39:12,103.4,104.2,1.2,{NORMAL},1,2,
2,2,6,4,5,2015-07-30 12:17:12,2015-07-30 12:39:12,103.4,104.2,1.8,{BOOKING},1,2,
3,2,3,4,9,2015-07-30 10:17:12,2015-07-30 10:39:12,103.4,104.2,1.9,"{NORMAL,BOOKING}",1,2,

関連情報