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 :

Extraire une chaine entre 2 délimiteurs dans un fichier


Sujet :

Langage Perl

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut Extraire une chaine entre 2 délimiteurs dans un fichier
    Bonjour,

    J'aurais besoin d'un peu d'aide pour effectuer la chose suivante :

    Soit un fichier de la structure suivante :
    <cre>
    ......
    <type_msg>XXX</type_msg>
    ......
    </cre>

    La balise <cre></cre> se répetant à l'infini et sans utiliser la librairie de perl (parser), comment puis je extraire l'ensemble <cre></cre> en fonction de la valeur type_msg (103,202,204) et rediriger dans un fichier (W1,W2,W3) ?

    Merci pour votre aide.

  2. #2
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    J'ai essayé ceci, mais celà ne me sort rien. Je ne connait pas très bien Perl, pourriez vous m'aider ?

    use warnings;use strict;
    undef $/;
    my $fic = <>;
    pos($fic)=0;

    while ( $fic =~ /<cre>/gc ){
    print "toto5\n";
    if ($fic =~ / \G(.*<type_msg>103.*<\/cre>)/){
    print $1;
    }
    if ($fic =~ / \G(.*<type_msg>202.*<\/cre>)/){
    print $1;
    }
    if ($fic =~ / \G(.*<type_msg>204.*<\/cre>)/){
    print $1;
    }

    }

    Je n'ai pas réécrit dans un fichier pour le moment je voulais juste voir le résultat à l'écran.

  3. #3
    Membre confirmé
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Points : 558
    Points
    558
    Par défaut
    1) Utilise les balises CODE (le bouton # quand tu postes)
    2) Apprends à te servir correctement de l'opérateur <>
    3) Apprends à te servir correctement des expressions régulières.

    Pour les points 2 et 3, voir la FAQ et éventuellement les cours.
    There's nothing like $HOME!

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par Schmorgluck Voir le message
    1) Utilise les balises CODE (le bouton # quand tu postes)
    2) Apprends à te servir correctement de l'opérateur <>
    3) Apprends à te servir correctement des expressions régulières.

    Pour les points 2 et 3, voir la FAQ et éventuellement les cours.
    Ca c'est la réponse que j'attendais pour résoudre mon problème. Au lieu de joueur à Mr le blasé qui se permet de donner des leçons (j'irais quand même voir les points que tu souligne), il serait plus intelligent d'expliquer ne serait ce que rapidement ce qui ne va pas avec <> et l'expression régulières. Un jour quand tu seras grand tu comprendras.

  5. #5
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    ^^ et faut pas vous battre pour si peu. Marc a essayé d'écrire un script, ça montre sa bonne volonté, on peut quand même l'aider et le conseiller.

    Je ne suis pas certaine d'avoir tout compris. Tu as un fichier texte contenant plusieurs fois les balises "cre" et et voudrait récupérer les informations comprises entre celles-ci et les traiter différemment selon la valeur comprise entre "type_msg". Que veux-tu récupérer exactement entre les "cre"?

    A ta place je lirais le fichier ligne par ligne, je ne vois pas d'autres moyen surtout si tu as plusieurs fois les balises "cre". Mais si cela est vraiment à l'infini, il y aura un problème. Il y doit y avoir d'autres façons de procéder, mais je ne sais pas lequelles.


    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
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #!/usr/local/bin/perl
     
    use strict;
    use warnings;
     
    my $InFile = "P:/Perl/scripts/Files/test.txt";
    open (InFile,"$InFile") or die "Can't open file\n";
    my $Ligne;
     
    # $TexteRecup récupération du texte de <cre> à </cre>
    my $TexteRecup = "";
     
    my $Var = 0;
    my $Nombre;
     
    # lecture du fichier ligne par ligne
    while ($Ligne=<InFile>)
    {
     
            if($Ligne =~ /<cre>/)
            {
                    $Var = 1;
            }
            if ($Var == 1)
            {
                    # récupération des informations comprises entre les deux balises cre
                    $TexteRecup = $TexteRecup.$Ligne;
            }
            if($Ligne =~ /<type_msg>(\d*)<\/type_msg>/)
            {
     
                    $Nombre = $1;
            }
            if($Ligne =~ /<\/cre>/)
            {
     
                    if ($Nombre == 103)
                    {
                            print "103 => ".$TexteRecup."\n";
                            # traitement 1
                    }
                    elsif ($Nombre == 202)
                    {
                            print "202 => ".$TexteRecup."\n";
                            # traitement 2
                    }
     
                    # remise à 0 de la variable $Var et $TexteRecup
                    # pour le bloc <cre>...<\cre> suivant
                    $Var = 0;
                    $TexteRecup = "";
            }
     
     
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    / \G(.*<type_msg>103.*<\/cre>)/
    pourquoi \G ? pour que la recherche soit globale?
    Il faut écrire //g

    Si tu veux récupérer ce qui est entre <type_msg> et </cre> tu dois lire l'info sur plusieurs lignes or le "." signifie n'importe quel caractère sauf les sauts de lignes (\n).



    Jasmine,
    -- Jasmine --

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    ^^ et faut pas vous battre pour si peu.
    Désolé je suis un peu sanguin. Et puis j'attendais de l'aide pas des reproches à l'état pur.

    Citation Envoyé par Jasmine80 Voir le message
    Je ne suis pas certaine d'avoir tout compris. Tu as un fichier texte contenant plusieurs fois les balises "cre" et et voudrait récupérer les informations comprises entre celles-ci et les traiter différemment selon la valeur comprise entre "type_msg". Que veux-tu récupérer exactement entre les "cre"?
    Tout ce qui s'y trouve. Sinon tu as parfaitement compris mon besoins.

    Citation Envoyé par Jasmine80 Voir le message
    Mais si cela est vraiment à l'infini, il y aura un problème.
    A l'infini, disons que l'on peut trouver celà au moins 200 fois, c'est le nombre d'enregistrement que je reçoit par flux.

    Sinon, merci pour ton aide, celà fonctionne bien, et me tire une sacrée épine du pied.

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    pourquoi \G ? pour que la recherche soit globale?
    Il faut écrire //g

    Si tu veux récupérer ce qui est entre <type_msg> et </cre> tu dois lire l'info sur plusieurs lignes or le "." signifie n'importe quel caractère sauf les sauts de lignes (\n).
    Et bien le \G (assertion) si je ne m'abuse se couple avec le /g (d'avant). Pour moi il me permettait de rechercher et récuperer avec le '.*' tous ce qu'il y vait entre <type_msg> et </cre>Entre temps j'avais modifié le début :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while ( $fic =~ /<cre>/gmc ){
    pour préciser que la recherche pouvait être multilignes.
    Ainsi pour moi comme on partait de la position 0 et que l'on s'interessait à <cre>, dès qu'on le trouvait on récuperait tout et en fonction de l'expression \G je récuperer toute la suite jusqu'à </cre>.
    Comme la recherche était globale, la position était sauvegardé et on continuait la lecture du fcihier.

  8. #8
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Ah oui, tu as raison je ne connais pas cela.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    \G  Reconnait l'endroit ou s'est arrete le precedent m//g
    Si tu veux récupérer tout ton fichier dans une variable et puis l'analyser, il faudrait utiliser un contexte de liste. Le récupérer dans un variable scalaire comme tu veux le faire, semble impossible.
    Pour lire depuis un descripteur de fichier ouvert on utilise l'opérateur < < >>. Dans un contexte scalaire, cet opérateur lit une ligne du fichier associé. Dans un contexte de liste, il lit l'intégralité du fichier en rangeant chaque ligne dans un élément de la liste.
    http://perl.enstimac.fr/DocFr/perlintro.html

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    my $InFile = "P:/Perl/scripts/Files/test.txt";
    open (INFILE,"$InFile") or die "Can't open file\n";
    my @fich = <INFILE>;
    Tu peux retrouver 200 fois ton bloc ... raison de plus pour lire le fichier ligne par ligne comme je te l'ai montré dans mon script. Il suffit de l'adapter pour ne récupérer que ce que tu souhaites comme informations.
    N'hésite pas si tu as d'autres questions.

    Jasmine,
    -- Jasmine --

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    Oki doki.

    Merci.

  10. #10
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    N'oublie pas de cocher la case "résolu" si tu n'auras plus de questions.

    Bon travail,


    Jasmine,
    -- Jasmine --

  11. #11
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Citation Envoyé par Jasmine80 Voir le message
    Si tu veux récupérer tout ton fichier dans une variable et puis l'analyser, il faudrait utiliser un contexte de liste. Le récupérer dans un variable scalaire comme tu veux le faire, semble impossible.
    Sisi, c'est possible, il faut simplement indiquer à Perl qu'il ne doit pas lire ligne par ligne, l'idiome correspondant est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    open my($file), '<', $file_path
      or die "Can't open $file_path : $!\n";
    my $file_content = do { local $/; <$file> };
    close $file;
    Qui utilise une astuce pour localiser au maximum le changement de mode de lecture.
    Note que grâce au "undef $/" le code initial était presque correct (il y avait des erreurs de regexp).

    Attention cependant, .* est gourmand, il va essayer de matcher un maximum de caractère, y compris d'éventuels </cre> avant de matcher la suite, il vaudrait mieux utiliser .*?, à part cette erreur, il manquait également les modifieurs /s et /c sur certaines regexps.

    On pourrait faire quelque chose comme cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/usr/bin/perl
    use warnings; use strict;
     
    my $fic = do {local $/; <>};
     
    while ( $fic =~ m{<cre>( .*? )</cre>}smxg ){
      my $cre_content = $1;
      if( $cre_content =~ m{<type_message>103} ) {
        # blabla
      }
      # autres types de message
    }
    Néanmoins lire ligne par ligne est sans doute une meilleure idée si tes fichiers sont vraiment gros.

    --
    Jedaï

  12. #12
    Membre confirmé
    Avatar de Schmorgluck
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    371
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Mai 2006
    Messages : 371
    Points : 558
    Points
    558
    Par défaut
    Citation Envoyé par MarcCC Voir le message
    Ca c'est la réponse que j'attendais pour résoudre mon problème. Au lieu de joueur à Mr le blasé qui se permet de donner des leçons (j'irais quand même voir les points que tu souligne), il serait plus intelligent d'expliquer ne serait ce que rapidement ce qui ne va pas avec <> et l'expression régulières.
    Désolé, j'étais crevé, et l'absence de balises CODE m'avait énervé. Mais, honnêtement, je ne voyais pas très bien comment défricher ton problème plus efficacement qu'en te renvoyant à la FAQ.
    There's nothing like $HOME!

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    @Schmorgluck : Pas de soucis, moi je m'emporte vite alors
    @Jedai : Merci à toi pour le debug clair du code

    Sinon, voici une autre solution que l'on m'a fournie, celà peut peut être interesse du monde :

    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
    20
    21
     
    #!/usr/bin/perl
    use strict;use warnings;
     
    open LIRE,"ton_fichier"
      or die "E/S : $!\n";
     
    my (@fic,@res);
     
    while(<LIRE>){
      push @fic,$_ if /<cre>/ .. /<\/cre>/;
    }
     
    @res = split /<\/cre>/, join "",@fic;
    pop @res;
    foreach (@res){
      $_ =~ />(\d{3})</;
      open ECRIRE,">>$1.txt" or die "E/S : $!\n" if $1;
      print ECRIRE "$_</cre>" if $1;
      close ECRIRE;
    }
    Par contre pour de gros fichiers je ne sait pas ce que celà vaut.

  14. #14
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    C'est pas trop mal, par contre ça fait un certain nombre d'assomptions que je n'ai pas osé faire, par exemple ça ne marche que si <cre> commence sa ligne et </cre> finit sa ligne, par ailleurs le split(join()) est un peu crade et pas très efficient, également il suppose qu'il n'y a que le type de message qui forme un champ composé de 3 chiffres dans ton fichier, de plus il sait ce que tu veux faire de tes messages. En bref ça a été écrit par quelqu'un qui en sait plus sur ton fichier que ce que tu nous a dit, ou qui assume beaucoup de choses gratuitement.

    Le plus efficace reste probablement l'idée de Jasmine80 (je n'ai pas regardé son script en détail par contre).

    --
    Jedaï

  15. #15
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    26
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 26
    Points : 9
    Points
    9
    Par défaut
    @Jedai :
    Il assume gratuitement

    Sinon je suis bien d'accord que ligne par ligne est mieux. Celà me permet en plus de rajouter d'autres tests plus facilement, ce que j'ai d'ailleurs fait.

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

Discussions similaires

  1. Extraire une chaine entre 2 caractères identiques
    Par nicomax34 dans le forum Langage
    Réponses: 3
    Dernier message: 28/01/2014, 10h39
  2. extraire une chaine entre un mot et un caractére
    Par gastoncs dans le forum VB.NET
    Réponses: 25
    Dernier message: 10/01/2012, 18h20
  3. [RegExp] Récupérer une chaine entre deux délimiteurs
    Par Soncar dans le forum Général JavaScript
    Réponses: 8
    Dernier message: 22/02/2011, 21h07
  4. Extraire une chaine entre parenthèse
    Par flo73 dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 16/10/2010, 12h14
  5. Extraire une chaine entre guillemets
    Par grenouille2008 dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 01/07/2008, 16h40

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