Séparateur d'échappement entre guillemets, en awk
j'utilise awk pour analyser mes données avec", " comme séparateur car l'entrée est un fichier csv. Cependant, il y a "," dans les données qui s'est échappé par des guillemets ("...").
exemple
filed1,filed2,field3,"field4,FOO,BAR",field5
Comment puis-je ignorer la virgule "," dans les le double devis afin que je puisse analyser les données en sortie correctement à l'aide de awk? Je sais que nous pouvons le faire dans excel, mais comment nous le faisons dans awk?
3 réponses
c'est facile, avec 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
ajout de quelques commentaires selon L'exigence de L'OP.
De la GNU awk manuel :
la valeur de FPAT devrait être une chaîne qui fournit une expression. Cette expression régulière décrit le contenu de chaque champ. Dans le cas des données CSV présentées ci-dessus, chaque champ est soit "tout ce qui est pas une virgule", ou "une double citation, quelque chose de ce n'est pas une double citation, et une double citation finale."S'il est écrit que une constante d'expression régulière (voir Chapitre 3 [Expressions régulières], page 37), nous aurions /([^,]+)|("[^"]+")/. Ecrire ceci sous forme de chaîne nous oblige à échapper aux doubles guillemets, conduisant à: FPAT = "([^,]+)|(\"[^\"]+\")"
FPAT fonctionne quand il y a des lignes et des virgules à l'intérieur des champs cités, mais pas quand il y a des guillemets doubles, comme ceci:
field1,"field,2","but this field has ""escaped"" quotes"
vous pouvez utiliser un programme d'enrubannage simple que j'ai écrit appelé csvquote pour rendre les données faciles à interpréter par awk, puis restaurer les caractères spéciaux problématiques, comme ceci:
csvquote inputfile.csv | awk -F, '{print }' | csvquote -u
voir https://github.com/dbro/csvquote pour code et docs
parseurs CSV à part entière tels que Perl Text::CSV_XS
sont conçus pour gérer ce genre de bizarrerie.
supposons que vous voulez seulement imprimer le 4ème champ:
perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new()} if($csv->parse($_)){ @f=$csv->fields(); print "\"$f[3]\"" }' file
la ligne d'entrée est divisée en tableau @f
La zone 4 est $f[3]
puisque Perl commence l'indexation à 0
j'ai fourni plus d'explication de Text::CSV_XS
dans ma réponse ici: analyse fichier csv utilisant gawk