Script Perl pour compter une occurence dans une ligne avec mots

laisso -  
[Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   -
Bonjour,

J'ai des difficultés à exécuter ce script.

# Date 11/11/2014

#Demander à l'utilisateur de saisir autant de mots qu'il le souhaite. Il signale la fin de la saisie en entrant "@".
#Ensuite, la liste des mots qu'il a saisis est affichée dans l'ordre alphabétique avec le nombre d'occurrences de chaque mot dans la liste (un mot par ligne).

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;
use Term::ANSIColor qw(:constants);
use List::Util qw(min max);
use List::Util qw(sum);
my $i=0;
my @L1;

print "saisissez autant de mots que vous le désirez: " ;
my $mots= <>;
chomp $mots;
say "vous avez saisi: $mots";

while ($mots !=@) {

$L1[$i]=$mots ;
$i++ ;
print "saisissez autant de mots que vous le désirez : " ;
$mots= <> ;
chomp $mots ;
say "vous avez saisi :$mots" ;

}

say(BOLD,RED,"> Terminé !",RESET) ;

foreach $line (@fcont) {
$compte =()= $line =~ /\s/g;
$compte++;
print FOUT $compte;
print FOUT "\n"

2 réponses

  1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Salut laisso,

    Oui, effectivement :

    $ ./laisso.pl 
    syntax error at ./laisso.pl line 22, near "$i"
    syntax error at ./laisso.pl line 28, near "}"
    Global symbol "$line" requires explicit package name at ./laisso.pl line 32.
    Global symbol "@fcont" requires explicit package name at ./laisso.pl line 32.
    Global symbol "$compte" requires explicit package name at ./laisso.pl line 33.
    Global symbol "$line" requires explicit package name at ./laisso.pl line 33.
    Global symbol "$compte" requires explicit package name at ./laisso.pl line 34.
    Global symbol "$compte" requires explicit package name at ./laisso.pl line 35.
    Missing right curly or square bracket at ./laisso.pl line 36, at end of line
    syntax error at ./laisso.pl line 36, at EOF
    ./laisso.pl has too many errors.


    Tu dois faire
    while ($mots !="@") {
    , puisque le symbole "@" est un caractère.

    Tu dois déclarer avec
    my
    toutes les variables que tu utilises.

    Il manque une accolade fermante à ta boucle foreach à la fin.

    Cela dit :

    - @fcont sort de nulle part, cela ne serait pas plutôt @L1 ?
    - tu ne fais aucun tri alphabétique
    - tu veux faire quoi exactement avec
    $compte =()= $line =~ /\s/g; 
    , en tout état de cause, cela cela n'affichera un décompte que pour chaque ligne du tableau

    Si j'étais toi, je mettrais les mots en tant que clefs d'un hash, dont la valeur serait la valeur numérique correspondant au nombre d'occurrences. Ensuite, tu tries ton hash selon les clefs avec foreach et sort, et tu affiches les clefs et leurs valeurs.

    Dal
    1
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      au temps pou rmoi,
       while ($mots !="@")
      est incorrect car l'opérateur de comparaison de chaînes doit aussi être changé, c'est
      while ($mots ne "@")
      , qui est correct.

      Autrement, avec strict et warnings, tu as tous les messages d'erreur à la compilation, et à l'exécution, qui devraient permettre de te rendre compte que :

      -
      print: "@L2";
      est incorrect et que tu dois écrire
      print "@L2";
      ,
      -
      foreach $line (@L2) {
      utilise une variable $line non déclarée, donc tu dois écrire
      foreach my $line (@L2) {
      ,
      -
      print FOUT $compte;
      utilise un identifiant de fichier non ouvert, ni déclaré, pourquoi ne pas faire simplement
      print "$compte\n";
      ?

      voilà le code corrigé

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      use 5.010;
      use Term::ANSIColor qw(:constants);
      use List::Util qw(min max);
      use List::Util qw(sum);
      my $i=0;
      my @L1;
      my $compte=0;
      my @L2;
      
      
      print "saisissez autant de mots que vous le désirez: " ;
      my $mots= <> ;
      chomp $mots ;
      say "vous avez saisi: $mots";
      while ($mots ne "@") {
          $L1[$i]=$mots ;
          $i++ ;
          print "saisissez autant de mots que vous le désirez : " ;
          $mots= <> ;
          chomp $mots ;
          say "vous avez saisi :$mots" ;
      }
      
      @L2=sort @L1;
      print "@L2";
      
      say(BOLD,RED,"> Terminé !",RESET) ;
      
      foreach my $line (@L2) {
          $compte =()= $line =~ /\s/g;
          $compte++;
          print "$compte\n";
      } 


      sur un exemple de saisies, cela donne cela :

      $ ./laisso_corr.pl
      saisissez autant de mots que vous le désirez: un
      vous avez saisi: un
      saisissez autant de mots que vous le désirez : deux deux
      vous avez saisi :deux deux
      saisissez autant de mots que vous le désirez : trois trois trois
      vous avez saisi :trois trois trois
      saisissez autant de mots que vous le désirez : quatre quatre quatre quatre
      vous avez saisi :quatre quatre quatre quatre
      saisissez autant de mots que vous le désirez : @
      vous avez saisi :@
      deux deux quatre quatre quatre quatre trois trois trois un> Terminé !
      2
      4
      3
      1


      c'est assez illisible, surtout si tu as beaucoup de mots différents, et tu n'affiches pas un mot par ligne avec le nombre de fois que ce mot apparaît.

      pourquoi ne procèdes-tu pas comme suggéré dans mon message précédent avec un hash trié par clefs ?

      Dal
      0
    2. laisso
       
      Nous n'avons pas vue encore cet aspect du chapitre. Nous nous sommes arrêté dans le chapitre liste. Pour le reste c'est compliqué. J'en suis à mon premier cours de perl avec ce type d'exercice donc c'est difficile et besoin de quelqu'un qui m'aide à corriger mes fautes.
      0
    3. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      j'ai corrigé les erreurs de syntaxe, mais ton code ne fonctionne pas vraiment, à moins que des mots identiques soient saisis sur les mêmes lignes (comme dans mon exemple).

      En fait :

      - ton code trie alphabétiquement chaque ligne et crée un tableau avec le résultat
      - l'expression
      $compte =()= $line =~ /\s/g;
      compte les espaces dans chaque ligne, et tu incrémentes de 1 le résultat, mais cela ne fait que compter les espaces (dans chaque ligne du tableau trié), et pas les occurrences des mots

      Pour une solution avec un hash, voir mon nouveau post avec un exemple de code.


      Dal
      0
  2. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Dans le monde réel, pour faire cela, on utiliserai un hash, c'est absurde de faire autrement en Perl.

    et c'est aussi simple que cela :

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my %hash;
    print "saisissez autant de lignes de mots séparés " .                                                                                                                                                              
        "par des espaces que vous le désirez (saisir " .
        "@ sur une ligne pour terminer) :\n" ;
    while ((my $mots = <>) ne "@\n") {
        chomp $mots;
        foreach my $mot (split /\s+/, $mots) {
            $hash{$mot}++;
        }
    }
    foreach my $mot (sort keys %hash) {
        print "Mot $mot :\t$hash{$mot} fois\n";
    }
    


    ce qui donne :

    $ ./laisso_corr2.pl 
    saisissez autant de lignes de mots séparés par des espaces que vous le désirez (saisir @ sur une ligne pour terminer) :
    il était un petit navire
    il était un petit navire
    qui n'avait ja ja jamais navigué
    qui n'avait ja ja jamais navigué
    ohé ohé
    ohé ohé matelot
    matelot navigue sur les flots
    @
    Mot flots : 1 fois
    Mot il : 2 fois
    Mot ja : 4 fois
    Mot jamais : 2 fois
    Mot les : 1 fois
    Mot matelot : 2 fois
    Mot n'avait : 2 fois
    Mot navigue : 1 fois
    Mot navigué : 2 fois
    Mot navire : 2 fois
    Mot ohé : 4 fois
    Mot petit : 2 fois
    Mot qui : 2 fois
    Mot sur : 1 fois
    Mot un : 2 fois
    Mot était : 2 fois

    Dal
    1
    1. laisso
       
      Merci. J'ai choisi d'appliquer ce code plus apte à mon gout. Bien que mon code soit aussi fonctionnel mais moins performants et moins puissants.

      Merci de votre aide.
      0
    2. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      Mais je croyais que tu disais ne pas pouvoir utiliser les hash parce qu'ils n'avaient pas été enseignés ?

      N'oublie pas de me citer en tant qu'auteur de ce code, ainsi tu respecteras la licence CreativeCommons applicable : https://www.commentcamarche.net/infos/25861-informations-de-copyright/ et je te souhaite bonne chance :-)

      Sinon, je te confirme de nouveau que ton code ne fonctionnait pas vraiment, en fin de compte. Essaye de lui passer les mêmes entrées que le mien, et tu verras le résultat.


      Dal
      0
    3. laisso
       
      Il y a une diapo sur le hash. Je viens juste d'en voir l'utilité. Merci en tout cas. J'en ai d'ailleurs parlé avec mon responsable de formation qui m'autorise à m'aider des forums.
      0
    4. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      ok, c'est super. Tu peux donc me citer sans crainte :-)
      0