数値列と文字列列を含むカンマ区切りのファイルがあります。文字列列は引用符で囲まれており、引用符の間にカンマがある場合があります。列を識別する方法は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
。
インストール
cpanm
(Perlを使用している場合は後で感謝します)$ sudo apt-get install cpanminus
Debian ベースのシステムを使用していない場合は、ディストリビューションのパッケージマネージャを使用してインストールできます。
Text::CSV
モジュールの取り付け$ sudo cpanm Text::CSV
ファイルの解析
$ 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
レコードはカンマで終わりますが(awk
asに渡されます-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}'`