3
votes

Comment lire un fichier csv dans des tableaux et le comparer et le remplacer par des entrées d'un autre fichier csv?

J'ai deux fichiers csv file1.csv et file2.csv .
file1.csv contient 4 colonnes.

file1:

awk -F'"(,")?' '
NR==FNR { r[$2] = $3; next }
{ for (n in r) gsub(n,r[n]) } IGNORECASE=1' file2.csv file1.csv>output.csv

fichier2:

cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp

Donc, ce que j'essaie de faire est de lire file1.csv ligne par ligne, de placer chaque entrée dans un tableau puis de comparer le premier élément de ce tableau avec la première colonne de file2.csv code> et si une correspondance existe, remplacez la colonne1 et la colonne2 de fichier1.csv par la colonne correspondante de fichier2.csv

Donc, ma sortie souhaitée est:

"Header1","Header2","Header3"
"aaaaaaa","cat","dog"
"iiiiiii","doctor","engineer"
"mmmmmmm","sky","blue"

Je peux le faire lorsqu'il n'y a qu'une colonne à remplacer.
Voici mon code:

Header1,Header2,Header3,Header4
aaaaaaa,bbbbbbb,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
iiiiiii,jjjjjjj,kkkkkkk,lllllll
mmmmmmm,nnnnnnn,ooooooo,ppppppp

Ma dernière étape consiste à vider le tableau entier dans un fichier de 10 colonnes. Des suggestions pour améliorer ou corriger mon code?


6 commentaires

En voyant votre profil, vous avez appris que, parmi les dernières questions, vous ne sélectionnez aucune réponse comme bonne, alors demandez-vous de le faire (après un certain temps après votre publication) et lorsque vous voyez suffisamment de réponses à votre message, vous pouvez sélectionner n'importe qui des répondez correctement à l'un d'entre eux @Anuj Kulkarni


@Tiw oui mon fichier2.csv peut avoir des guillemets. Je crée moi-même file2.csv tandis que file1.csv est un fichier généré par un outil. Ainsi, lors de la création de file2.csv, j'avais utilisé des guillemets.


@Tiw oui c'est correct. Il n'y aura pas de virgule. J'utilise les guillemets car file2 peut avoir plus de deux mots séparés par des espaces (comme une phrase).


@AnujKulkarni. Il est toujours conseillé de publier des échantillons proches du ou des Input_file (s), veuillez modifier votre message et nous le faire savoir.


Anul si votre entrée est séparée par des virgules, alors un vide ou une tabulation est comme n'importe quel autre caractère, vous n'avez pas besoin de mettre des guillemets autour de vos champs sauf s'ils contiennent une virgule ou une nouvelle ligne. Peuvent-ils contenir des nouvelles lignes?


@EdMorton non, il n'y aura pas de nouvelles lignes.


3 Réponses :


3
votes

EDIT: Considérant que votre Input_file2 a la date au format "ytest", "test2" etc si oui, essayez de suivre. (Merci à Tiw d'avoir fourni ces exemples dans son message) XXX



Pourriez-vous s'il vous plaît essayer de suivre.

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  a[tolower($1)]=$0
  next
}
a[tolower($1)]{
  print a[tolower($1)],$NF
  next
}
1'  Input_file2  Input_file1

OU au cas où vous pourriez avoir une combinaison de lettres minuscules et majuscules dans Input_file (s) puis essayez de suivre.

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  a[$1]=$0
  next
}
a[$1]{
  print a[$1],$NF
  next
}
1'  Input_file2  Input_file1


1 commentaires

Merci pour les efforts que j'expérimente avec votre code en ce moment.



2
votes

Compte tenu de vos exemples de données et de la description de vos commentaires, veuillez essayer ceci:
(À en juger par votre propre code, vous pouvez avoir des guillemets autour des champs, donc je n'ai pas essayé de répondre.)

awk 'BEGIN{FS=OFS=","}
    NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");k=tolower($1);a[k]=$2;b[k]=$3;next}
    {k=tolower($1);if(a[k]){$2=b[k];$1=a[k]}}
    1' file2.csv file1.csv

Eg:

awk 'BEGIN{FS=OFS=","}
    NR==FNR{for(i=1;i<=NF;i++)$i=gensub(/^"(.*)"$/,"\\1",1,$i);a[$1]=$2;b[$1]=$3;next}
    $1 in b{$2=b[$1];}
    $1 in a{$1=a[$1];}
    1' file2.csv file1.csv

Une autre façon, plus verbeuse, mais je pense que c'est mieux pour vous de comprendre (GNU awk):

$ cat file1.csv
Header1,Header2,Header3,Header4
aaaaaaa,bbbbbbb,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
iiiiiii,jjjjjjj,kkkkkkk,lllllll
mmmmmmm,nnnnnnn,ooooooo,ppppppp

$ cat file2.csv
"Header1","Header2","Header3"
"aaaaaaa","cat","dog"
"iiiiiii","doctor","engineer"
"mmmmmmm","sky","blue"

$ awk 'BEGIN{FS=OFS=","}
NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");a[$1]=$2;b[$1]=$3;next}
$1 in a{$2=b[$1];$1=a[$1];}
1' file2.csv file1.csv
Header2,Header3,Header3,Header4
cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp

Notez un piège ici, puisque $ 1 code > est la clé, nous devrions donc changer $ 1 en dernier.

Une solution insensible à la casse:

awk 'BEGIN{FS=OFS=","}
    NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");a[$1]=$2;b[$1]=$3;next}
    $1 in a{$2=b[$1];$1=a[$1];}
    1' file2.csv file1.csv

Pour un code concis, ajout de la variable k et déplacement de "if" à l'intérieur.


2 commentaires

merci comme vous l'avez dit, la deuxième méthode était plus facile à comprendre. J'ai essayé de l'utiliser et cela fonctionne.


@AnujKulkarni Bien sûr, je suis content que cela ait aidé :)



2
votes

Avec n'importe quel awk et n'importe quel nombre de champs dans l'un ou l'autre fichier:

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    gsub(/"/,"")
    key = tolower($1)
}
NR==FNR {
    for (i=2; i<=NF; i++) {
        map[key,i] = $i
    }
    next
}
{
    for (i=2; i<=NF; i++) {
        $(i-1) = ((key,i) in map ? map[key,i] : $(i-1))
    }
    print
}

$ awk -f tst.awk file2 file1
Header2,Header3,Header3,Header4
cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp


1 commentaires

Le code dans le bloc NR == FNR stocke les valeurs de file2 dans le tableau de la carte un champ à la fois et la boucle dans le 2ème bloc accède aux valeurs de ce tableau un champ à la fois.