Chaine de caractère

Bonjour,

Je travaille sous PERL.

J'ai différentes lignes d'informations.
La 1ere ligne commence par l'expression "INFO : Close File".
Ma deuxieme ligne commence par diférents mots: soit type,soit reception.
Ma derniere ligne commence tjrs par "FIN IMPORT".

Exemple de fichiers :
INFO : Close File........................
Reception................
.....
FIN IMPORT...................

OU/ET

INFO : Close File........................
Type................
.....
FIN IMPORT...................

Je veux créer un txt pour les lignes d'infos dont la 2eme ligne commence par "type" et un autre txt dont la 2eme ligne commence par "reception".
Voila ce que j'ai fait mais le hic c'est qu'en faisant ca, je perd la 1ere ligne:

while (<FICHIER>) {
print WRITER if /Reception/ .. /FIN IMPORT/;
\n;

}

Je veux garder la 1ere ligne automatiquement.
Merci pour votre aide.
Configuration: Windows XP
Internet Explorer 7.0

10 réponses

  • Votes
  • Date
  • Date décroissante
Résumé de la discussion

Le problème porte sur un script PERL qui lit des blocs de texte: la première ligne est INFO : Close File, la deuxième commence par type ou Reception, et la dernière ligne est FIN IMPORT. Pour répondre, la solution propose d’ouvrir le fichier source et deux fichiers de sortie, de mémoriser la ligne INFO et d’imprimer le bloc complet dans le fichier correspondant entre le début et FIN IMPORT. De plus, le script peut être étendu pour écrire les blocs dans des fichiers distincts en fonction de mots-clés supplémentaires et peut être adapté à d’autres noms de balises.

Bobot (l’IA à votre service)
  1. bonjour,

    j'ai un fichier de ce type :

    INFO : Close File........................
    Reception................
    .....
    FIN IMPORT...................

    INFO : Close File........................
    Type................
    .....
    FIN IMPORT...................

    Je veux créer un txt pour les lignes d'infos dont la 2eme ligne commence par "type" et un autre txt dont la 2eme ligne commence par "reception".

    J'ai fait ce code mais ca marche pas comme je veux:
    open FICHIER,"<P:\\Prog_perl\\Infos_pivot1.txt"
    or die "Ce fichier n'existe pas!";

    open WRITER, ">P:\\Prog_perl\\Tab1_type.txt"
    or die "Le fichier ne peut etre édité!";

    $ligne =<FICHIER> ;

    foreach ($ligne) {
    if (substr($ligne,48)="Reception"){
    print WRITER;
    }
    }

    __END__

    Ce que je veux au final c'est avoir un txt avec des infos de ce type:

    INFO : Close File........................
    Type ................
    .....
    FIN IMPORT...................

    INFO : Close File........................
    Type................
    .....
    FIN IMPORT...................

    Et je veux un autre txt de ce type :

    INFO : Close File........................
    Reception................
    .....
    FIN IMPORT...................

    INFO : Close File........................
    Reception................
    .....
    FIN IMPORT...................

    Donc un fichier qui concerne les receptions et un autre, le type.

    Quelqu'un peut il m'aider svp?
    Merci d'avance
    1. Contributeur
      Salut.
      Moi, dans mes comparaison de chaine j'utilise "eq" car le symbole égale me posait des problèmes.
      if(substr($ligne,9) eq 'Reception')
      Ensuite, il faut faire un tampon en algo :
      TANT pas à la fin du fichier.
      tampon=$ligne
      $ligne=<FICHIER>
      if($ligne == "recepction")
      impression de tampon dans fichier1
      tant que $ligne différent de FIN_IMPORT
      lire une ligne et imprimer dans le fichier 1
      Sinon, si $ligne == "type"
      impression de tampon dans fichier2
      tant que $ligne différent de FIN_IMPORT
      lire une ligne et imprimer dans le fichier 2
      fin tant que
      1. C'est normal qu'avec '==' tu aies des problèmes, car Perl fait une comparaison en numérique; il va donc transtyper les 2 chaînes en numériques, si bien que: "toto" == "titi" est vrai puique tous deux égaux à zéro.
        De même "toto" = 0 est vrai mais "toto" = 1 est faux.
        Donc '==' pour les comparaisons numériques et 'eq' pour les comparaisons de chaînes; de même pour les autres opérateurs de comparaison (comparaison, différent, inférieur, ...), à chacun son opérateur.
      2. Merci pour ta reponse.
        J'ai essayé de transcrire ton algo mais il y a des petits trucs qui doivent pas aller:

        open FICHIER,"<P:\\Prog_perl\\Infos_pivot1.txt"
        or die "Ce fichier n'existe pas!";

        open WRITER, ">P:\\Prog_perl\\Tab1_type.txt"
        or die "Le fichier ne peut etre édité!";

        open WRITER2, ">P:\\Prog_perl\\Tab2_type.txt"
        or die "Le fichier ne peut etre édité!";

        $ligne =<FICHIER> ;
        while (pas la la fin du fichier) # Comment fait on pour dire kon est pas a la fin du fichier ?{
        $ligne =<FICHIER> ;
        tampon=$ligne;
        if ($ligne=="Reception"){
        print WRITER;
        while ($ligne ne 'FIN IMPORT'){
        print $ligne ; #Lire la ligne est ce bien cela?
        print WRITER;
        }
        }
        elsif ($ligne=="Reception"){
        print WRITER2;
        while ($ligne ne 'FIN IMPORT'){
        print $ligne ;
        print WRITER2;
        }

        }

        }
        close (FICHIER)
        close (WRITER)
        close (WRITER2)

        _END_
      3. Contributeur
        @flongoune syntaxe, pour lire une ligne, c'est :
        $ligne=<FICHIER>
        print c'est pour écrire et il faut préciser le fichier de sortie.
        Donc :
        open FICHIER, WRITE1et WRITE 2
        while (<FICHIER>) # Je crois qu'on peut faire comme ça
        {
        $ligne =<FICHIER> ;
        $tampon=$ligne;
        $ligne=<FICHIER>
        if ($ligne eq "Reception"){
        print WRITER "$tampon";
        while ($ligne ne 'FIN IMPORT'){
        print WRITER $ligne ;
        $ligne=<FICHIER>
        }
        }
        elsif ($ligne eq "Type"){
        ...#la même chose qu'au dessus mais avec WRITE2
        }

        }

        }
        etc.

        À Fiddy : je sais que tu as donné la réponse, mais je pense que ça peut lui être utile pour la suite qu'on lui corrige son programme. (Enfin, vu mon niveau en perl, il doit rester de belles boulette). Ton programme est bien compact, mais il pique les yeux d'un débutant comme moi ;)
    2. Contributeur
      Salut,
      Voici un programme fait à la va-vite (donc sûrement optimisable) :
      #!/usr/bin/perl 
      use strict;use warnings;
      
      open(LIRE, "nomFichier") || die("erreur ouverture");
      open(WRITE1, ">reception") || die("erreur écriture");
      open(WRITE2, ">type") || die("erreur écriture");
      
      my @buf=();
      my $type;
      while(<LIRE>){
          @buf=() if /INFO/;
          if(@buf==1){
              /(\S*)/;
              $type=$1;
          }
          push(@buf,$_) if /INFO/ .. /FIN IMPORT/;
      
          if(/FIN IMPORT/){
              print WRITE1 @buf if $type eq 'Reception';
              print WRITE2 @buf if $type eq 'Type';
          }
      }
      
      close(LIRE);
      close(WRITE1);
      close(WRITE2);
      

      Cdlt
      1. Je te remercie.

        J'ai pas tres bien compri ton code, ce qui fait que j'ai du mal a trouver ce qui ne vas pas.
        Quand je le lance, j'ai le message d'erreur suivant :
        erreur ouverture at P:\Prog_perl\Fiddy.pl line 6.
        Je me suis dit qu'il y a avait un souci sur les ouvertures de fichier mais c pas ca!

        Ca peut etre koi?
    3. Contributeur
      Remplace nomFichier par le nom de ton fichier ^^.
      open(LIRE, "nomFichier") || die("erreur ouverture");
      1. Salut Fiddy,

        Je te remercie de m'avoir donné un coup de main. Ca marche! Merci bcp.
        Si possible, pourrais tu m'expliquer ce petit programme stp? Si tu as le temps!
        cordialement
      2. Contributeur
        Remplace nomFichier par le nom de ton fichier
        Ha ! oui, tout de même !
        Petit rappel : il n'est pas interdit d'utiliser son cerveau avant de recopier quelque chose.
      3. @Char SnipeurJe sais que je suis novice dans ce langage mais je ne suis pas bete au point de ne pas remplacer nomFichier par le nom de mon fichier !

        Comment on fait pour dire qu'il y a un espace en début de chaine?
      4. Contributeur
        @flongoVoici le programme commenté :
        #!/usr/bin/perl 
        use strict;use warnings;
        
        open(LIRE, "nomFichier") || die("erreur ouverture");
        open(WRITE1, ">reception") || die("erreur écriture");
        open(WRITE2, ">type") || die("erreur écriture");
        
        my @buf=(); #déclaration et initialisation de @buf
        my $type; #déclaration de $type
        while(<LIRE>){ #tant qu'il y a des lignes à lire
            @buf=() if /INFO/; #si la ligne contient INFO, alors @buf=(), début d'un nouveau cycle
            if(@buf==1){ #si @buf ne contient qu'un seul élément, donc à la deuxième ligne
                /(\S*)/; #on sauvegarde le premier mot dans $1
                $type=$1; #on sauvegarde dans $type
            }
            push(@buf,$_) if /INFO/ .. /FIN IMPORT/; #on empile s'il s'agit du bon paragraphe
        
            if(/FIN IMPORT/){ #s'il s'agit de la ligne FIN IMPORT
                print WRITE1 @buf if $type eq 'Reception'; #on copie dans WRITE1 si $type vaut Reception
                print WRITE2 @buf if $type eq 'Type'; #on copie dans WRITE2 si $type vaut Type
            }
        }
        
        close(LIRE);
        close(WRITE1);
        close(WRITE2);
        
        
    4. Contributeur
      Dit plutôt ce que tu ne comprends pas.
      les '/' correspondent à des testes sur les chaîne de caractère en écriture raccourci.
      1. Dans le prog, c koi le tampon? A quoi il sert reelement?

        On peut pas mettre $tampon=<FICHIER>, au lieu de:
        $ligne =<FICHIER> ;
        $tampon=$ligne;
        $ligne =<FICHIER>;

        ??????????????

        Je t'ai remi le prog:

        open FICHIER,"<P:\\Prog_perl\\Infos_pivot1.txt"
        or die "Ce fichier n'existe pas!";

        open WRITER, ">P:\\Prog_perl\\Tab1_type.txt"
        or die "Le fichier ne peut etre édité!";

        open WRITER2, ">P:\\Prog_perl\\Tab2_type.txt"
        or die "Le fichier ne peut etre édité!";

        while (<FICHIER>){
        $ligne =<FICHIER> ;
        $tampon=$ligne;
        $ligne =<FICHIER>;
        if ($ligne eq 'Reception'){
        print WRITER "$tampon";
        while ($ligne ne 'FIN IMPORT'){
        print WRITER $ligne;
        $ligne =<FICHIER>;
        }
        }
        elsif ($ligne eq 'Type'){
        print WRITER2 "$tampon";
        while ($ligne ne 'FIN IMPORT'){
        print WRITER2 $ligne;
        $ligne =<FICHIER>;
        }

        }

        }
        close (FICHIER);
        close (WRITER);
        close (WRITER2);

        En ce qui concerne l'espace en debut de caractère, j'ai trouvé ca:
        if $type eq /\sERROR/ (ca fonctionne). Est vraiment ca ou on pouvait faire autrement?

        Merci pour ton aide!
    5. Contributeur
      Ha ! c'est mon programme que tu ne comprends pas ?
      en effet, il n'y a pas besoin de faire $ligne=<FICHIER> puis $tampon=$ligne, tu peux faire directement $tampon=<FICHIER>
      Le tampon sert car tu lis un fichier un fichier ligne par ligne et que l'information sur où écrire est stocké à la deuxième ligne. Il faut donc sauvegarder la première ligne quelque part en attendant de savoir où la mettre.
      Il y a deux approche : la mienne qui utilise ce tampon et écris ensuite ligne par ligne dans le fichier.
      Et la solution de fiddy qui utilise un tampon plus gros (buf) où il stocke le bloc entier (de INFO à FIN IMPORT) avant de l'écrire dans le bon fichier suivant le type de la deuxième ligne lue.
      D'autre question ?
      1. En faite, ca marche tjrs pas! Je cherche la ou ca va pas!

        Pourquoi, ne vaudrait il pas mieux attribuer $tampon=<FICHIER> des le début et non dans la boucle?

        Voila ce ke j'ai modifié:

        open FICHIER,"<P:\\Prog_perl\\Infos_pivot1.txt"
        or die "Ce fichier n'existe pas!";

        open WRITER, ">P:\\Prog_perl\\Tab1_type.txt"
        or die "Le fichier ne peut etre édité!";

        open WRITER2, ">P:\\Prog_perl\\Tab2_type.txt"
        or die "Le fichier ne peut etre édité!";

        $tampon=<FICHIER>;
        while (<FICHIER>){
        if ($tampon eq 'Reception'){
        print WRITER $tampon;
        while ($tampon ne 'FIN IMPORT'){
        print WRITER $tampon;
        #$tampon =<FICHIER>;
        }
        }
        elsif ($tampon eq 'Type'){
        print WRITER2 $tampon;
        while ($tampon ne 'FIN IMPORT'){
        print WRITER2 $tampon;
        #$tampon=<FICHIER>;
        }

        }

        }
        close (FICHIER);
        close (WRITER);
        close (WRITER2);

        Merci
    6. Contributeur
      ba non, il ne faut pas affecté tampon avant la boucle, sinon il ne sert que pour le premier bloc.
      Une chose est sur, tu n'as rien compris à ce que je t'ai expliqué. Que ça soit mon programme ou celui de fiddy, il faut utiliser 2 variables car l'information est à la deuxième ligne.
      Par contre, je pense que je fait une grosse erreur avec while(<FICHIER>) car d'après ce qu'à écris fiddy, c'est la même chose que while($_=<FICHIER>), tu lit donc une ligne du fichier.
      open FICHIER, WRITE1et WRITE 2
      while (<FICHIER>)
      {
        $tampon=$_;
        $ligne=<FICHIER>
        if ($ligne eq "Reception"){
          print (WRITER, "$tampon");
          print (WRITER ,$ligne) ;
          while ($ligne ne 'FIN IMPORT'){
            $ligne=<FICHIER>
            print (WRITER ,$ligne) ;
          }
        }
        elsif ($ligne eq "Type"){
      ...#la même chose qu'au dessus mais avec WRITE2
         }
      
        }
      
      } 
      1. Contributeur
        if ($ligne eq "Reception"){
        Ca ne marchera pas, il n'y a pas comparaison stricte (des informations après Reception, et un \n en fin de ligne)

        Voici une version correcte (j'ai essayé de garder la même structure) :
        my $tampon;
        my $ligne;
        
        open(FICHIER, "nomFichier") || die("erreur ouverture");
        open(WRITER1, ">reception") || die("erreur écriture");
        open(WRITER2, ">type") || die("erreur écriture");
        
        while ($tampon=<FICHIER>) # Je crois qu'on peut faire comme ça
        {
            while($tampon eq "\n"){ #au cas où il y a des lignes vierges entre les paragraphes
                $tampon=<FICHIER>;
            }
            $ligne=<FICHIER>;
            if ($ligne =~ /Reception/ ){
                print WRITER1 "$tampon";
                print WRITER1 $ligne;
                while ($ligne !~ /FIN IMPORT/){
                    $ligne=<FICHIER>;
                    print WRITER1 $ligne;
                }   
            }   
            elsif ($ligne =~ /Type/){
                print WRITER2 "$tampon";
                print WRITER2 $ligne;
                while ($ligne !~ /FIN IMPORT/){
                    $ligne=<FICHIER>;
                    print WRITER2 $ligne;
                }
            }
        }   
        
        close(FICHIER);
        close(WRITER1);
        close(WRITER2);
        
        


        Cdlt
      2. Modérateur
        @fiddySalut,

        while ($tampon=<FICHIER>) # Je crois qu'on peut faire comme ça
        {
        while($tampon eq "\n"){ #au cas où il y a des lignes vierges entre les paragraphes
        $tampon=<FICHIER>;
        }
        $ligne=<FICHIER>;


        pour verifier les lignes vides il suffit d'utiliser la regex ^$
        next if /^$/; # je ne traite pas les lignes vides

        Utiliser l'opérateur <> deux fois dans la boucle je n'ai jamais vu

        Quand tu fais
        while($tampon=<FICHIER>){
        ici $tampon contiendra une par une les lignes de fichiers
        donc $ligne recevra plutôt le contenu de $tampon;
        }

        D'ailleurs plutôt logique pour le nom des variables sera
        while($ligne=<FICHIER>){
           $tampon=$ligne;
        }


        Si le mode slurp n'est pas activé
        $var=<FICHIER> contient la 1ère ligne de fichier
      3. Contributeur
        @lami20jJe sais bien, mais j'ai essayé d'adapter sa version de programme en restant le plus simple possible. Ma version (sûrement contestable ^^) a été donné en #5.
      4. Modérateur
        @fiddyRe,

        Je n'ai pas des moyens pour tester.
        Veux-tu tester le code de message 21?
        Merci.
      5. Contributeur
        @lami20jSalut.
        pour $tampon, c'est ce que j'avais proposer au début, mais c'est vrai que ça ne change rien, ça fait économisé une ligne.
        éclaire nous sur le comportement de $var=<FICHIER>. D'après le message que tu mets, si je comprends bien, soit cette commande met une ligne dans la variable et passe à la ligne suivante lors du prochain appel, soit elle met la première ligne du fichier dans la variable à chaque appel (mais alors comment lire les autres lignes ?), ceci selon slurp est activé ou non. C'est ça ?
        Sinon, qu'est-ce qui te choque d'utiliser deux fois l'opérateur <> dans une boucle ?
        (Il est vrai que j'écris en perl comme j'écrirais en C, et que certaines subtilités m'échappent)
    7. Contributeur
      Bien vu fiddy ! j'y avait pensé au premier message, puis oublié après.
      1. Modérateur
        Salut,

        Pourquoi pas (je n'ai pas testé ;-) un truc de genre
        #!/usr/bin/perl 
        use strict; use warnings;
        
        open FICHIER,  "nomFichier"      or die "E/S $!\n";
        open RECEPTION,">>reception.txt" or die "E/S : $!\n";
        open TYPE,     ">>type.txt"      or die "E/S : $!\n";
        
        while (<FICHIER>) { 
          my $info=$_ if /^INFO/;
          print RECEPTION "$info $_" if /Reception/ .. /FIN IMPORT/; 
          print TYPE      "$info $_" if /Type/      .. /FIN IMPORT/;
        }
        __END__


        1. Contributeur
          Ton programme donne des warnings :
          Use of uninitialized value $info in concatenation (.) or string at ./lami.pl line 10, <FICHIER> line 2.
          ...
          Use of uninitialized value $info in concatenation (.) or string at ./lami.pl line 11, <FICHIER> line 24.
          

          Sinon pour le résultat, il n'affiche pas la ligne INFO.
        2. Modérateur
          @fiddyRe,

          Merci ;-)
          Je vais voir à la maison ce soir.
          Mais il sera intéressant d'avoir le fichier ou au moins une partie de fichier pour tester.
        3. @fiddyMerci, ca fonctionne!

          Ou je pourrai trouver le module drivers DBD::mysql. J'en ai besoin car je dois faire une base de données en mysql.
        4. Modérateur
          @flongoSalut,

          Tu diras peut être quel code fonctionne ;-))
          Ensuite pour les modules il faut voir sur cpan.org
      2. Modérateur
        Re,

        Si tu as installer activeperl tu peux ouvrir dos et taper ppm pour installer des modules depuis cpan