it-swarm-id.com

Melarikan pemisah dalam tanda kutip ganda, dalam awk

Saya menggunakan awk untuk mem-parsing data saya dengan "," sebagai pemisah karena inputnya adalah file csv. Namun, ada "," di dalam data yang lolos dengan tanda kutip ganda ("...").

Contoh

filed1,filed2,field3,"field4,FOO,BAR",field5

Bagaimana saya bisa mengabaikan koma "," di dalam tanda kutip ganda sehingga saya dapat mengurai output dengan benar menggunakan awk? Saya tahu kita bisa melakukan ini di Excel, tetapi bagaimana kita melakukannya dengan awk?

26
joomanji

Sangat mudah, dengan GNU awk 4 :

zsh-4.3.12[t]% awk '{ 
 for (i = 0; ++i <= NF;)
   printf "field %d => %s\n", i, $i
 }' FPAT='([^,]+)|("[^"]+")' infile
field 1 => filed1
field 2 => filed2
field 3 => field3
field 4 => "field4,FOO,BAR"
field 5 => field5

Menambahkan beberapa komentar sesuai persyaratan OP.

Dari GNU manual awk :

Nilai FPAT harus berupa string yang memberikan ekspresi Reguler. Ekspresi reguler ini menjelaskan konten dari setiap bidang . Dalam kasus data CSV seperti yang disajikan di atas, setiap bidang adalah Baik "apa pun yang bukan koma," atau "kutipan ganda, apa pun Yang bukan kutipan ganda, dan penutup double quote. ”Jika ditulis sebagai konstanta ekspresi reguler (lihat Bab 3 [Ekspresi Reguler], halaman 37), kita akan memiliki/([^,] +) | (" [^ "] +") /. Menulis ini sebagai string Mengharuskan kita untuk keluar dari tanda kutip ganda, mengarah ke: FPAT = "([^,] +) | (\" [^\"] + \") "

21
Dimitre Radoulov

FPAT berfungsi ketika ada baris baru dan koma di dalam bidang yang dikutip, tetapi tidak ketika ada tanda kutip ganda, seperti ini:

field1,"field,2","but this field has ""escaped"" quotes"

Anda dapat menggunakan program pembungkus sederhana yang saya tulis bernama csvquote untuk membuat data mudah bagi penerjemah awk, dan kemudian mengembalikan karakter khusus yang bermasalah, seperti ini:

csvquote inputfile.csv | awk -F, '{print $4}' | csvquote -u

Lihat https://github.com/dbro/csvquote untuk kode dan dokumen

11
D Bro

Parser CSV yang sepenuhnya lengkap seperti Text::CSV_XS Perl dibuat khusus untuk menangani keanehan semacam itu. 

Misalkan Anda hanya ingin mencetak bidang ke-4:

Perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){ @f=$csv->fields(); print "\"$f[3]\"" }' file

Baris input dibagi menjadi array @f
Field 4 adalah $f[3] sejak Perl mulai mengindeks pada 0 

Saya memberikan penjelasan lebih lanjut tentang Text::CSV_XS dalam jawaban saya di sini: parse file csv menggunakan gawk

1
Chris Koknat