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

Langage Perl Discussion :

Aide : Refaire mon programme awk en perl


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Informatique
    Inscrit en
    Mai 2017
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Informatique

    Informations forums :
    Inscription : Mai 2017
    Messages : 19
    Par défaut Aide : Refaire mon programme awk en perl
    Hello,

    J'ai un programme awk qui compte et affiche les 5 mots qu'on trouve le plus dans un fichier. Je souhaite le faire en perl, j'ai essayé plein de trucs, mais je dois vous avouez que je sèche un peu (beaucoup même). C'est pourquoi je demande de l'aide.

    Voici mon programme en awk

    Code awk : 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
    20
    #!/usr/bin/awk -f
     
    {
    $0=tolower($0); #On met tout en minuscule
    gsub(/[^a-z0-9_ \t]/,"",$0) #On enleve les carac indésirables
     
    #on insère ou incrémente les occurences de ts les mots de la ligne courante
    for (i = 1; i<=NF; i++)
    	tab_des_frequences[$i]++;
     
    }
     
    END {
     
    #affichage
    commande_de_fin="sort +1 -nr | head -5" ; #tri numérique décroissant ou flux de sortie et 6 premiers
    for (mot in tab_des_frequences) #Pr ts les mots trouvés dans le text
    	if (tab_des_frequences[mot]>1)
    	printf "%s\t%d\n", mot, tab_des_frequences[mot] | commande_de_fin;
    }


    Et voici ce que j'ai essayé en perl (je sais très bien que ma boucle For est fausse car "for in" n'existe pas en perl"

    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
    #!/usr/bin/perl
    use strict;
    use warnings;
     
     
    my $i;
    $_ = lc; #met les caractères de la ligne courante en miniscule
    my @tab_ligne = split("[^a-z0-9_]"); #découpe selon la ponctuation
    while (<>)
    {
    	my @tab_freq[$i]++;
    }
     
    open(FHO, '| sort -n | tail -5'); 
    for (my $mot in my @tab_freq[$i])
    	if ($tab_freq[$mot]>1)
    	printf FHO "%25s\t%d\n", $tab_freq{$mot},$mot;

    Merci d'avance

  2. #2
    Expert confirmé Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 986
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 986
    Par défaut
    En Perl, il n'y a pas par défaut de tableaux associatifs comme dans d'autres langages qui associent une clef à une valeur tout en conservant un ordre précis et qui puissent éventuellement être triés.
    Par contre Perl a des hashs qui associent une clef à une valeur, mais dont l'ordre est indéterminé.
    La manœuvre consiste donc à comptabiliser les occurrences dans un hash, puis à trier le tableau des clefs du hash suivant les valeurs du hash.
    Il y a probablement mille et une manières d'écrire ça, en voici une:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #!/usr/bin/perl
    use strict;
    use warnings;
     
    my %occ; # hash: mot => nombre d'occurrence
     
    while(<>) { # boucle sur les lignes du fichier
        $_ ne "" && $occ{$_}++ for split /\W+/, lc $_;
    }
     
    my @keys = sort { $occ{$b} <=> $occ{$a} } keys(%occ); # trie les clefs de %occ suivant la valeur associée 
                                                          # et les stocke dans le tableau @keys
     
    print "$_\t$occ{$_}\n" for @keys;

  3. #3
    Membre averti
    Homme Profil pro
    Informatique
    Inscrit en
    Mai 2017
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Informatique

    Informations forums :
    Inscription : Mai 2017
    Messages : 19
    Par défaut
    Merci pour ta réponse. Et donc dans ton programme ,pour afficher que les 5 mots qui apparaissent le plus faut mettre quoi ?

  4. #4
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    A la fin du programme, le tableau @keys contient les mots triés par ordre d'occurrence décroissant (autrement dit, les mots les plus fréquents en tête). Il suffit donc d'imprimer les cinq premiers mots de ce tableau:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print "@keys[0..4]", "\n";  # les cinq mots séparés par des espaces sur la même ligne
    ou, pour avoir un mot par ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print "$_\n" for @keys;

  5. #5
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Wanheda Voir le message
    Et voici ce que j'ai essayé en perl (je sais très bien que ma boucle For est fausse car "for in" n'existe pas en perl"
    Ça existe presque, mais en plus simple.

    Il suffit de remplacer ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for (my $mot in my @tab_freq[$i])
    par ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for my $mot (@tab_freq) {
    Cela dit, il y a plusieurs autres erreurs dans ton code, mais je n'ai pas le temps de les relever maintenant. Si ça t'intéresse pour progresser, je pourrai le faire ce soir (ou ce weekend).

    En ce qui concerne ton problème d'origine, à noter que Perl est livré avec un utilitaire, a2p, qui traduit du code awk en code Perl (mais le code Perl produit n'est pas forcément très lisible, je préfère personnellement la solution de la réécriture).

  6. #6
    Membre averti
    Homme Profil pro
    Informatique
    Inscrit en
    Mai 2017
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Informatique

    Informations forums :
    Inscription : Mai 2017
    Messages : 19
    Par défaut
    Merci beaucoup le programme marche

    Si ça t'intéresse pour progresser, je pourrai le faire ce soir (ou ce weekend).
    Je veux bien

  7. #7
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Bonsoir,

    voici une analyse assez détaillée de ton code.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    #!/usr/bin/perl
    use strict;
    use warnings;
    Très bien d'utiliser ces deux pragmas, ce n'est pas obligatoire (du point de vue du compilateur, ça peut marcher sans), mais c'est beaucoup plus qu'obligatoire, c'est essentiel (sauf à la rigueur pour un programme uniligne). Bref, continue à les utiliser.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    my $i;
    $_ = lc; #met les caractères de la ligne courante en miniscule
    my @tab_ligne = split("[^a-z0-9_]"); #découpe selon la ponctuation
    Tout cela ne fait rien d'utile (et, de toute façon, ça ne compile sûrement pas), parce qu'en fait, à ce point, tu n'as pas encore commencé à lire le fichier en entrée.

    Par défaut, les instructions awk travaillent sur chaque ligne en entrée (fichier en entrée ou STDIN). Ce n'est pas le comportement par défaut de Perl. Il existe des options de la ligne de commande de Perl l'amenant à fonctionner à peu près de la même façon (options -n et - p), mais en fonctionnement normal, il faut commencer par ouvrir le fichier puis le lire explicitement ligne à ligne, ou alors, au minimum, à lire l'entrée standard (STDIN).

    Là, tu commences vraiment à lire les données en entrée. C'est dans le bloc ouvert par ces instructions que tu dois commencer à traiter tes lignes en entrée.

    Le reste, ça n'a plus vraiment de sens, je ne vais pas vraiment commenter.

    Essayons de réécrire ton programme en s'en éloignant le moins possible. Je veux essentiellement: lire l'entrée standard ligne à ligne, splitter chaque ligne sur les caractères autres que des lettres, des chiffres et _, pour chaque mot ainsi obtenu stocker une fréquence dans un hash. Quand j'ai fini de lire les données en entrée, je veux trier mes données stockées par ordre de fréquence et afficher les cinq les plus fréquentes.
    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
     
    #!/usr/bin/perl
    use strict;
    use warnings;
    my %tab_freq;
    while (<>)
    {
        chomp; # élimine les caractères de fin de ligne de la ligne courante ($_)
        $_ = lc $_;        #met les caractères de la ligne courante ($_) en minuscule
        my @tab_ligne = split /\W+/, $_; #découpe la ligne courante selon les caractères autres que des lettres, chiffres et _
        for my $word (@tab_ligne) {      # pour chaque mot de la ligne
            $tab_freq{$word}++;            # incrémenter la fréquence pour ce mot
        }
    }
    # On a maintenant dans %tab_freq un histogramme de la fréquence des mots, on peut trier par fréquence
    my @sorted_histo = sort { $tab_freq{$b} <=> $tab_freq{$a} } keys %tab_freq;
    print "@sorted_histo[0..4]";
    J'ai fait un test minimal, ça a l'air de marcher, mais il y a peut-être des cas particuliers à vérifier ou des points de détails à reprendre.

  8. #8
    Membre averti
    Homme Profil pro
    Informatique
    Inscrit en
    Mai 2017
    Messages
    19
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Informatique

    Informations forums :
    Inscription : Mai 2017
    Messages : 19
    Par défaut
    D'acc merci je comprend mieux. Par contre dans ce programme ça affiche bien les 5 mots les plus courant mais ne les compte pas.

    Sinon j'ai une petite question, que fait : $tab_freq{$b} <=> $tab_freq{$a}

  9. #9
    Membre confirmé
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Mars 2015
    Messages
    138
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Morbihan (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Service public

    Informations forums :
    Inscription : Mars 2015
    Messages : 138
    Par défaut
    Citation Envoyé par Wanheda Voir le message
    Sinon j'ai une petite question, que fait : $tab_freq{$b} <=> $tab_freq{$a}
    <=> fait une comparaison numérique entre les valeurs des clés $a et $b de la table de hachage $tab_freq et retourne -1, 0 ou 1 en fonction du résultat :
    -1 si $tab_freq{$b} est inférieur à $tab_freq{$a}
    0 si $tab_freq{$b} est égal à $tab_freq{$a}
    1 si $tab_freq{$b} est supérieur à $tab_freq{$a}

  10. #10
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Wanheda Voir le message
    D'acc merci je comprend mieux. Par contre dans ce programme ça affiche bien les 5 mots les plus courant mais ne les compte pas.
    Si tu veux afficher les fréquences, il suffit d'ajouter le code voulu en modifiant comme suit la fin du programme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    my @sorted_histo = sort { $tab_freq{$b} <=> $tab_freq{$a} } keys %tab_freq; # trie les mots selon leur fréquence d'apparition
    for my $word (@sorted_histo[0..4]) {
        print "$word : $tab_freq{$word} \n";
    }

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

Discussions similaires

  1. Réponses: 8
    Dernier message: 30/05/2013, 13h28
  2. Aide avec mon programme decryptage MD5
    Par hacker59 dans le forum VB.NET
    Réponses: 0
    Dernier message: 19/05/2013, 20h20
  3. Aide pour mon programme
    Par vg-matrix dans le forum Débuter
    Réponses: 19
    Dernier message: 23/06/2009, 15h42
  4. Aide pour mon programme en C# SVP
    Par eurikain dans le forum ASP.NET
    Réponses: 1
    Dernier message: 11/01/2008, 15h53
  5. besoin d'aide pour mon programme
    Par pouyoudu17 dans le forum Débuter avec Java
    Réponses: 11
    Dernier message: 28/05/2007, 22h18

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