CSVファイルの文字列値でコンマを処理する

CSVファイルの文字列値でコンマを処理する

数値列と文字列列を含むカンマ区切りのファイルがあります。文字列列は引用符で囲まれており、引用符の間にカンマがある場合があります。列を識別する方法はFS =","

サンプル記録

"prabhat,kumar",19,2000,"bangalore,India"

存在するAWKしなければならない

$1 = "prabhat,kumar"
$2 = 19
$3 = "2000"
$4 = "bangalore,india"

設定FS=","によって問題が発生します。

入力は次のとおりです

"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"
"prabhat,kumar",19,2000,"bangalore,India","ABC,DEF","GHI",123,"KLM","NOP,QRS"

出力は次のようになります。

"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"
"prabhat,kumar"|19|2000|"bangalore,India"|"ABC,DEF"|"GHI"|123|"KLM"|"NOP,QRS"

私が試しているコード:

awk -F"," '{for(i=1;i<=NF;i++){if(i%NF==0){ORS="\n"} {if($i ~ /^\"/ || $i ~ /\"$/) {a=a OFS $i;j++;{if(j%2==0){sub(/^\,/,X,a); print a;j=0;a=""}}} else {print $i}}} {ORS="|"}}' ORS="|" OFS=, p.txt

答え1

まず、適切なCSVパーサーを使用する必要があります。たとえば、Perlでは次のものを使用できますText::CSV

  1. インストールcpanm(Perlを使用している場合は後で感謝します)

    $ sudo apt-get install cpanminus
    

    Debian ベースのシステムを使用していない場合は、ディストリビューションのパッケージマネージャを使用してインストールできます。

  2. Text::CSVモジュールの取り付け

    $ sudo cpanm Text::CSV
    
  3. ファイルの解析

    $ perl -MText::CSV -le '
        $csv = Text::CSV->new({binary=>1}); 
        while ($row = $csv->getline(STDIN)){
        print "1:$row->[0], 2:$row->[1], 3:$row->[2], 4:$row->[3]"}' < file.csv 
    1:prabhat,kumar, 2:19, 3:2000, 4:bangalore,India
    

    上からわかるように、最初のフィールドは$row->[0]、2番目のフィールド$row->[1]などです。


これが正しい方法です。より簡単ですが汚れた方法は、引用符で囲まれたコンマを別の文字に置き換えることです。その後、通常どおり使用awkし、最後にコンマに戻ります。ここではこれを使用していますが、###フィールドの1つには決して現れないと確信しているすべてを使用できます。

$ sed -r 's/("[^",]+),([^",]+")/\1###\2/g' file.csv | 
    awk -F, '{print $1,$3}' | sed 's/###/,/g'
"prabhat,kumar" 2000

答え2

GNUがある場合awk

$ awk -vFPAT='[^,]*|"[^"]*"' '{ gsub("^\"|\"$","",$1); gsub("^\"|\"$","",$4); print $1 $4} '
prabhat,kumarbangalore,India

$1出力形式は印刷のみして並んでいるので少し見苦しいです$4。自分の好みに合わせて変更できると確信しています。

フィールドの周りに二重引用符を保持する必要がある場合は、これら2つのgsub();関数を削除してください。

説明する:

通常、awkレコードのフィールドは(FieldSeparator)変数の内容で区切られ、デフォルト FSはスペース(タブ、スペース、および改行)です。区切り文字は、awkレコードが終了する場所を示します。ファイル内のcsvレコードはカンマで終わりますが(awkasに渡されます-vFS=,)、もちろんあなたのような例では単純すぎて壊れることがあります。

またはFPAT(フィールドパターン)定義のレコードですawk。レコードの終了位置を指定する代わりに、レコード全体をawk含む定義を作成します。あなたの例は複雑なので、csvこれは[^,]*|"[^"]*"

故障は次のとおりです。 -

  • [^,]カンマ以外の文字(*)をできるだけ多く使用してください。 2 つのコンマ間の内容はすべてフィールドです。
  • または(|
  • 一重引用符(")の後に二重引用符がない場合()、[^"]できるだけ数回()*の後に一重引用符(")が続きます。カンマを含む二重引用符内のすべての項目は、1つのフィールドとして計算されます。

答え3

RubyはCSVの解析に非常に便利です。

ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|")' file
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS
prabhat,kumar|19|2000|bangalore,India|ABC,DEF|GHI|123|KLM|NOP,QRS

出力に引用符はありません。これは、フィールド区切り文字を含むフィールドがないためです。引用符が必要な場合は、すべてのフィールド(整数を含む)を強制的に引用符で囲むことができます。

ruby -rcsv -ne 'puts CSV.generate_line(CSV.parse_line($_), :col_sep=>"|",:force_quotes=>true)' file
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"
"prabhat,kumar"|"19"|"2000"|"bangalore,India"|"ABC,DEF"|"GHI"|"123"|"KLM"|"NOP,QRS"

答え4

これは私にとって効果的です。

$ echo '"prabhat,kumar",19,2000,"bangalore,India"' | 
  awk -F, '{print $1,$2,$3,$4,$5,$6}'| 
    awk -F\" '{print $2,$3,$4}'|awk -F\  '{print $1","$2,$3,$4,$5","$6}'`

関連情報