Unix:連続するコンマを見つけて、連続するパイプラインに置き換えます

Jan 08 2021

Unixで二重引用符で囲まれたCSVをパイプライン区切りのtxtファイルに変換しています。次のsedコマンドを使用して、「、」を|に置き換えました。次に、開始と終了の二重引用符を削除します。

sed -e 's/","/|/g' -e 's/"//g' filenm.csv > filenm.txt

しかし、ファイルには二重引用符のない連続したコンマがあるようで、それらは置き換えられていません。

Col1|col2|col3|col4|col5|col6|col7|col8
Val1|val2|val3,,,,val7|val8

ここで、これらの連続するすべてのコンマを、空またはnullフィールドを示す連続するパイプラインに変換したいと思います。

また、他のフィールドにも、変更してはならないフィールド値内にコンマがあります。

そのために以下を使ってみましたが、うまくいきませんでした。

sed -e 's/,{1,\}/|{1,\}/g' filenm.csv > filenm.txt

メモ帳で開いたサンプルcsvファイル:

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

これが問題の再現と解決に役立つことを願っています。

前もって感謝します....

回答

2 WiktorStribiżew Jan 08 2021 at 22:37

あなたが使用することができますperl

perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' filenm.csv > filenm.txt

詳細

  • "([^"]*)"|,-に一致する正規表現パターン"。次に、以外の0個以上の文字をグループ1にキャプチャして"から、に一致する"か、,他のすべてのコンテキストでaに一致します。
  • defined($1) ? $1 : "|"-RHS、replacement。一致をグループ1の値(グループ1が一致した|場合)または(,一致した場合)のいずれかに置き換えます。
  • ge-gglobal(すべての出現箇所を置き換えます)をe表し、PerlにRHSをPerl式として扱わせます。

オンラインテストを参照してください:

#!/bin/bash
s='"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","0","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"'
perl -pe 's/"([^"]*)"|,/defined($1) ? $1 : "|"/ge' <<< "$s"

出力:

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|0|No.38,3rd st, RRR NNN, TRT||||9999999999
4 potong Jan 08 2021 at 23:05

これはあなたのために働くかもしれません(GNU sed):

sed -E ':a;s/^(("[^",]*",+)*"[^",]*),/\1\n/;ta;y/,\n/|,/' file

,'sの間の"'を改行で繰り返し置き換えてから、,'sを|' sに、改行を,'sに変換します。

1 RamanSailopal Jan 09 2021 at 00:35

awkの使用:

awk -F \" '{ for(i=1;i<=NF;i++) { if ($i ~ /^[,]{2,}$/) { $i="," } } OFS="\"";gsub("\",\"","\"|\"",$0)}1' sample.csv

説明:

awk -F \" '{  # Set the field delimiter to double quote
             for(i=1;i<=NF;i++) { 
               if ($i ~ /^[,]{2,}$/) { 
                  $i="," # Loop through each field and if is contains 2 or more commas, set that field to one comma } } OFS="\""; gsub("\",\"","\"|\"",$0) # Substitute "," for "|"
           }1' sample.csv
1 Daweo Jan 09 2021 at 01:50

私はそのためにGNUAWKを次のように使用します。してみましょうfile.txtコンテンツで

"ID","Name","DOB","Age","Address","City","State","Country","Phone number"
"123","ABC","12/20/2020","15","No.38,3rd st, RRR NNN, TRT",,,,"9999999999"
"456","DEF","12/20/2020",,,,,"test-country","9999999999"
"465","XYZ",,,"No.38,3rd st, RRR NNN, TRT",,,,"9999999999"

その後

awk 'BEGIN{FS="\"";OFS=""}{for(i=1;i<=NF;i+=2){$i=gensub(/,/,"|","g",$i)};print $0}' file.txt

出力

ID|Name|DOB|Age|Address|City|State|Country|Phone number
123|ABC|12/20/2020|15|No.38,3rd st, RRR NNN, TRT||||9999999999
456|DEF|12/20/2020|||||test-country|9999999999
465|XYZ|||No.38,3rd st, RRR NNN, TRT||||9999999999

最初と最後の列が空になることはないと思いました。私は"フィールドセパレーターとして使用し、次にすべての奇数フィールド(これらにはのみが含まれます,)ですべて,をに変更し|ます。最後に、そのような変更された行全体を印刷します。

(GNU Awk 5.0.1でテスト済み)