Je crée un script Bash pour générer une sortie à partir d'un fichier CSV (j'ai plus de 1000 entrées et je ne l'ai pas imaginée à la main ...).
Le contenu du fichier CSV semble semblable à Ceci: p> J'ai du code qui peut séparer les champs à l'aide de la virgule comme délimiteur, mais certaines valeurs contiennent des virgules, telles que actuellement, j'ai cette boucle: < / p> qui produit cette sortie pour les données d'échantillon indiquées ci-dessus: p> Comme vous pouvez le constater, la troisième entrée est analysée, la troisième entrée est analysée. incorrectement. Je veux qu'il produise p> adygeya, république code >. Ces valeurs sont entourées de citations pour indiquer que les caractères à l'intérieur doivent être traités dans le cadre du champ, mais je ne sais pas comment analyser cela pour en tenir compte. P>
6 Réponses :
Après avoir pensé au problème, j'ai compris que, puisque la virgule de la chaîne n'est pas importante pour moi, il serait plus facile de le supprimer simplement de l'entrée avant d'analyser.
à cette fin, j'ai Concocalisé une commande Cette solution ne fonctionne que lorsque la chaîne contient une seule virgule entre les guillemets doubles. P> La regex non évaluée est p> sed code> correspondant à des chaînes entourées de citations doublées contenant une virgule. La commande supprime ensuite les bits que vous ne voulez pas de la chaîne correspondante. Il le fait en séparant la regex en sections mémorisées. P> [Australian Capital Territory] [AU-ACT] [20034] [AU] [Australia]
[Piaui] [BR-PI] [20100] [BR] [Brazil]
[Adygeya Republic] [RU-AD] [21250] [RU] [Russian Federation]
[BÃo-BÃo] [CL-BI] [20154] [CL] [Chile]
Il y a quelques cas spécifiques où cela peut fonctionner et beaucoup de cas où il ne sera pas. Un problème significatif est que dans sed code> correspond à des correspondances telles que . * Code> sont gourmands.
Merci pour les commentaires. Avec mon contribution, je crois que cela fonctionnera bien, mais je suis intéressé à déterminer comment améliorer la solution générale. Serait-ce une amélioration? (") (^, *) (,) (^" *) (") code> apparemment sed code> ne prend pas en charge les correspondances paresseuses, mais une classe de caractères annulée peut fonctionner. Les devis échappés causeraient également des problèmes, j'attends
Après avoir regardé pour supprimer test: h3>
" code> vous pouvez tuyer la sortie à sed code>. p>
Merci, je ne sais pas pourquoi c'est wiki communautaire, mais je vais vérifier cela :)
@chrisbunney Depuis que j'ai pris la solution de Dimitire comme référence, je pensais qu'il serait inapproprié de prendre un crédit pour cette réponse. :)
Je viens de tester cela, il ne produit pas la même sortie pour moi que cela fait pour vous. En fait, il produit la même sortie "mauvaise" que j'ai décrite dans ma question
@chrisbunney ressemble à awk code> version de version. Je l'ai testé sur gnu-awk v 4.0.0 code>
Oui, avec un peu d'aide de @dimitre, il s'avère une ancienne version de Awk sur ma machine
Si vous voulez tout faire tout dans awk em> ( gnu awk 4 em> strud> est requis pour que ce script fonctionne comme prévu): awk '{
n = parse_csv($0, data)
for (i = 0; ++i <= n;) {
gsub(/,/, " ", data[i])
printf "[%s]%s", data[i], (i < n ? OFS : RS)
}
}
function parse_csv(str, array, field, i) {
split( "", array )
str = str ","
while ( match(str, /[ \t]*("[^"]*(""[^"]*)*"|[^,]*)[ \t]*,/) ) {
field = substr(str, 1, RLENGTH)
gsub(/^[ \t]*"?|"?[ \t]*,$/, "", field)
gsub(/""/, "\"", field)
array[++i] = field
str = substr(str, RLENGTH + 1)
}
return i
}' infile
Merci, il semble que mon installation de Debian 6 n'utilise pas AWK 4, j'ai supposé que le paquet aurait une version plus récente de Awk
Vous pouvez essayer la solution perl i> que je viens d'ajouter.
Accepté et +1, comme je pense que c'est la meilleure solution, même si ce n'est pas celui que je peux utiliser dans ce cas
Bonjour @chrisbunney, j'ai ajouté la version qui devrait fonctionner avec votre version awk i>.
en raison de la version légèrement dépassée de J'ai produit une utilité Script basé sur Ce blog post qui analyse le fichier CSV et Remplace les délimiteurs avec un délimiteur de votre choix afin que la sortie puisse être capturée et utilisée pour traiter facilement les données. Le script respecte les chaînes citées et les virgules intégrées, mais retirera les citations doubles qu'il trouve et ne fonctionnera pas avec des citations doubles évasées dans les champs. P> awk code> sur mon système et une préférence personnelle à coller à un script Bash, je suis arrivé une solution légèrement différente. #!/bin/bash
input=$1
delimiter=$2
if [ -z "$input" ];
then
echo "Input file must be passed as an argument!"
exit 98
fi
if ! [ -f $input ] || ! [ -e $input ];
then
echo "Input file '"$input"' doesn't exist!"
exit 99
fi
if [ -z "$delimiter" ];
then
echo "Delimiter character must be passed as an argument!"
exit 98
fi
gawk '{
c=0
$0=$0"," # yes, cheating
while($0) {
delimiter=""
if (c++ > 0) # Evaluate and then increment c
{
delimiter="'$delimiter'"
}
match($0,/ *"[^"]*" *,|[^,]*,/)
s=substr($0,RSTART,RLENGTH) # save what matched in f
gsub(/^ *"?|"? *,$/,"",s) # remove extra stuff
printf (delimiter s)
$0=substr($0,RLENGTH+1) # "consume" what matched
}
printf ("\n")
}' $input
Si vous pouvez tolérer que les citations environnantes persistent dans la sortie, vous pouvez utiliser un petit script que j'ai écrit appelé CSVQuote pour activer AWK et couper (et d'autres outils de texte UNIX) pour gérer correctement les champs cités qui contiennent des virgules. Vous enveloppez la commande comme ceci: voir https://github.com/ dbro / csvquote pour le code et la documentation p> p>
Utilisation de la solution de Dimitire (merci pour cela) J'ai remarqué que son programme ignore les champs vides.
Voici le correctif: P>
awk '{
for (i = 0; ++i <= NF;) {
substr($i, 1, 1) == "\"" &&
$i = substr($i, 2, length($i) - 2)
printf "[%s]%s", $i, (i < NF ? OFS : RS)
}
}' FPAT='([^,]*)|("[^"]+")' infile
Voir Stackoverflow.com/Questtions/7804673/...
Merci @tomwrittock, je vais enquêter sur le lien donné par cette réponse, je n'ai jamais utilisé
awk code> avant, il aura probablement besoin de swoter dessus (pour le bénéfice de tous les autres, le lien est: backreference.org/2010/04/17/csv-parsing-with-awk )Vous ne pouvez pas simplement réexporter les données avec '|', onglet ou un autre caractère qui n'apparaît pas dans l'entrée? Bonne chance.
@shellter Malheureusement, je n'ai pas de contrôle sur l'exportation des données
Également la recherche sur Google Groupes for comp.lang.awk. Il y a eu une discussion de 3 mois sur le traitement des CSV il y a 10 ans. Quelques solutions très sophistiquées. Bonne chance.
Similaire
@Denniswilliamson La réponse acceptée sur cette question est essentiellement «N'utilisez pas AWK pour traiter des données de CSV difficiles», cela ne m'aidait pas à traiter mes données, bien que cela aide à éliminer les options.
Ce n'est pas la seule chose qu'il dit. Il dit également d'utiliser un module Python ou Perl qui est composé spécialement pour le traitement des fichiers CSV.
N'ayant jamais utilisé Python / Perl, j'étais chiante de ça, pas une grande raison, mais ma motivation pour cela piratait ensemble quelque chose pour me sauver manuellement édition de quelques milliers de lignes dans un format spécifique ...