IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

AWK - Dedoublonner les mots d'un champs


Sujet :

Shell et commandes GNU

  1. #1
    Membre confirmé
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Par défaut [RESOLU] AWK - Dedoublonner les mots d'un champs
    Bonjour,

    Voilà j'ai fait pas mal de recherche sur notre ami google mais n'est pas trouvé de réponse à mon soucis
    Je m'explique, j'ai un fichier tabulé que je traite avec awk dans lequel je fais des substitutions etc..
    Dans le genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    1103153        BABA BABA GAGA        53         TATA GOGO TATA          TOTO
    Et je cherche à détecter les mots qui sont en double, voir en triple dans un champs afin qu'il n'en reste plus qu'un et donc avoir un resultat du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    1103153        BABA GAGA        53         TATA GOGO         TOTO
    Si quelqu'un a une idée je suis preneur, car pour le moment je trouve pas de solution et cela m'aiderai bien à éclaircir mon fichier ^^

    Merci

  2. #2
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Bonjour,

    Je ne connais pas de réponse toute faite. la commande awk par elle-même ne fait pas de "dédoublonnage". Mais il est possible d'appeler une commande système, du genre uniq. Cependant, pour qu'elle fonctionne, il faut auparavant trier les mots (les doublons doivent être consécutifs). Parce que sinon, voici le problème
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    echo -e "ZZ\nAA\nBB\nAA\nCC" | uniq
    ZZ
    AA
    BB
    AA   <-- pas supprimé!
    CC
    Il faut donc utiliser sort -u
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    echo -e "ZZ\nAA\nBB\nAA\nCC" | sort -u
    AA
    BB
    CC
    ZZ   <-- Plus dans l'ordre initial!
    Mais alors le résultat n'est plus dans l'ordre initial.

    Il faut donc préciser la demande: est-ce que l'ordre des sous-champs est important, ou bien?

  3. #3
    Membre confirmé
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Par défaut
    Désolé pour le retard ^^

    Donc non cela n'a rien de gênant que l'intérieur des champ se retrouve mélangé mais par contre cela l'est plus que l'opération se fasse à l'extérieur de mon script awk et que cela se fasse en ligne et non sur un champ ^^

    Je continue de chercher mais suis toujours preneur de trouvailles magiques

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2007
    Messages : 149
    Par défaut
    Bonjour, si ca peut t'aider j'aurais fait un truc comme ca :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #! /usr/bin/awk -f
     
    BEGIN {
        FS=" "
    }
    {
        path=""
        for (i = 1; i < (NF); i++) 
        {
     
           tabl_asso[$i]=$i
        }
     
        for (variable in tabl_asso)
        {
        	print variable
        }
     
    }

  5. #5
    Membre confirmé
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Par défaut
    Oui mais là cela travaille sur la ligne complète non?
    Moi ce que je cherche c'est à effectuer le déboulonnage par champ (voir sur un champ en particulier)

  6. #6
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    La solution se fait attendre... Je vais donc proposer quelque chose, mais comme il y a plusieurs d'inconnues, je fais les choix suivants:

    • Le séparateur de champ est '\t' (tabulation)
    • Le séparateur de sous-champ est ' ' (espace)
    • Le champ 3 est à modifier pour en extraire les doublons

    Voici les fichiers de départ et d'arrivée. J'ai mis un '\t' visible pour bien voir où ils sont situés.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    fichier_depart:
    champ 1 \t champ 2 \t AA BB AA CC \t champ 4
    champ 1 \t champ 2 \t ZZ AA ZZ CC \t champ 4
    fichier_arrivee:
    champ 1 \t champ 2 \t AA BB CC \t champ 4
    champ 1 \t champ 2 \t AA CC ZZ \t champ 4
    Voici le programme pur awk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    awk -F '\t' '
    {
    [01]  printf("%s\t%s\t", $1, $2)
    [02]  split($3, sousChamp, " ")
    [03]  taille = asort(sousChamp)
    [04]  nouveauChamp3 = ""
    [05]  for (i = 1; i <= taille - 1; i++)
    [06]  {
    [07]    if (sousChamp[i] != sousChamp[i + 1])
    [08]    {
    [09]      nouveauChamp3 = nouveauChamp3 sousChamp[i] " "
    [10]    }
    [11]  }
    [12]  nouveauChamp3 = nouveauChamp3 sousChamp[taille]
    [13]  printf("%s\t%s\n", nouveauChamp3, $4)
    }' fichier_depart > fichier_arrivee
    Explications:
    [01] Impression directe des champs précédents le champ 3 (pas de modif).
    [02] Découpage du champ 3 avec l'espace comme séparateur et remplissage du tableau nommé sousChamp. Les indices vont de 1 à n.
    [03] Tri du tableau. Les doublons sont maintenant consécutifs.
    Par exemple, pour la première ligne avant le tri il y a:
    sousChamp[1]: AA
    sousChamp[2]: BB
    sousChamp[3]: AA
    sousChamp[4]: CC
    Après le tri:
    sousChamp[1]: AA
    sousChamp[2]: AA
    sousChamp[3]: BB
    sousChamp[4]: CC
    [04] (Ré)-initialisation de ce que sera le champ 3.
    [05] La boucle for traverse le tableau jusqu'à l'avant dernière case.
    [07-09] Si la valeur de la case courante est différente de celle de la case suivante, alors la valeur courante est ajoutée à la fin de champ 3 (suivie d'un espace). Sinon, on n'ajoutera que la dernière valeur des cases identiques.
    [12] La dernière valeur du tableau mise dans le champ 3 (si c'est un doublon, les cases précédentes ne sont pas dans le champ 3).
    [13] Le nouveau champ 3 et le ou les suivants sont imprimés.

    Voili-voilou.

  7. #7
    Membre expérimenté
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Janvier 2007
    Messages : 149
    Par défaut
    Citation Envoyé par ssc37 Voir le message
    Oui mais là cela travaille sur la ligne complète non?
    Moi ce que je cherche c'est à effectuer le déboulonnage par champ (voir sur un champ en particulier)
    Slt l'ami, je ne comprends pas ton besoin peux-tu être plus clair ?

    Le code que j'ai posté obtient bien l'attendu à partir de l'existant en exemples dans ton premier post.


    Edit :

    Je vois que la solution que j'ai proposée fait la même chose que celle proposée par jmelyn.

    Je vais donc expliquer mon code :


    J'utilise un tableau associatif, pour chaque champ, je vais remplir le tableau d'index ce champ. En gros si tu as ta ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1103153        BABA BABA GAGA        53         TATA GOGO TATA          TOTO
    Voila ce qu'il se passe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    tabl_asso[1103153]=1103153;
    tabl_asso[BABA]=BABA;
    tabl_asso[BABA]=BABA;
    tabl_asso[GAGA]=GAGA;
    tabl_asso[53]=53;
    tabl_asso[TATA]=TATA;
    tabl_asso[GOGO]=GOGO;
    tabl_asso[TATA]=TATA;
    tabl_asso[TOTO]=TOTO;
    Pour le coup il y'a dédoublonage puisqu'on accède aux mêmes index . Pas besoin de tri.

    Si tu veux dédoublonner un champ en particulier passe le en argument.

  8. #8
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Pour DelWin,

    J'avais oublié cette caractéristique des tableaux associatifs. C'est un peu comme une map en C++. Cependant, la solution que tu proposes ne fonctionne pas car tu "dédoublonnes" sur la ligne entière. Or l'action est à faire uniquement sur un champ (j'ai pris le champ 3 dans mon exemple). Et passer le champ en argument oblige à triturer le fichier ensuite pour remplacer ledit champ.

    Je vais donc reprendre ce que j'ai fait en utilisant ce que tu proposes pour arriver à une solution plus élégante.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    awk -F '\t' '
    {
    [01]  printf("%s\t%s\t", $1, $2)
    [02]  split($3, champ3Avant, " ")
    [03]  delete champ3Apres
    [04]  for (index in champ3Avant)
    [05]  {
    [06]    champ3Apres[champ3Avant[index]] = "1"
    [07]  }
    [08]  for (index in champ3Apres)
    [09]  {
    [10]    printf("%s ", index)
    [11]  }
    [12]  printf("\t%s\n", $4)
    }' fichier_depart > fichier_arrivee
    Explications:
    [01] Impression directe des champs précédents le champ 3 (pas de modif).
    [02] Découpage du champ 3 avec l'espace comme séparateur et remplissage du tableau nommé champ3Avant. Les indices vont de 1 à n.
    [03]
    (Ré)-initialisation du tableau champ3Apres.
    [04] La boucle for traverse tout le tableau initial champ3Avant dans un ordre aléatoire.
    [06] À la fin de la boucle for, le tableau champ3Apres possède des cases contenant toutes n'importe quoi (j'ai mis "1"), mais dont les index sont les sous-champs qu'il faut dédoublonner. Si deux sous-champs sont identiques, ils affecteront deux fois "1" à la même case.
    [08] Nouvelle boucle for pour traverser le tableau final champ3Apres dans un ordre aléatoire.
    [10] Impression des index de champ3Apres qui sont les sous-champs dédoublonnés.
    [12] Impression des champs restants, ici uniquement $4.

    Dommage, je laisse un espace à la fin du champ 3.

  9. #9
    Membre confirmé
    Inscrit en
    Décembre 2008
    Messages
    57
    Détails du profil
    Informations forums :
    Inscription : Décembre 2008
    Messages : 57
    Par défaut
    Je m'excuse pour le retard j'ai eu une petite absence...

    Merci jmelyn et Delwyn, pour cette solution complété à 2 , qui correspond totalement à mes attentes et fonctionne parfaitement.

    En effet j'avais peut être pas été clair Delwyn concernant le déboulonnage que je voulais sur un seul champ mais ca va jmelyn à complété tout ca en y ajoutant ta touche ^^

    Merci vous 2 pour cette astuce bien utile et que je vais mettre de coté

    Passage en resolu

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Séparer les mots d'un champ
    Par aghilass dans le forum Développement
    Réponses: 4
    Dernier message: 04/04/2013, 17h34
  2. Réponses: 8
    Dernier message: 09/09/2009, 19h19
  3. Réponses: 2
    Dernier message: 27/08/2009, 17h10
  4. Réponses: 6
    Dernier message: 19/10/2008, 07h56
  5. Sélectionner les N premiers mots d'un champ texte
    Par keskispas dans le forum SQL
    Réponses: 19
    Dernier message: 22/01/2007, 14h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo