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 :

[Regex] pb reconnaissance multiligne avec lookahead


Sujet :

Langage Perl

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 36
    Par défaut [Regex] pb reconnaissance multiligne avec lookahead
    Bonjour,

    J'ai un souci avec une expression régulière.

    J'ai un fichier composé de n extraits.
    Chaque extrait est un ensemble de plusieurs lignes commençant toujours par :H10:HUB101 et ensuite, on peut avoir n’importe quoi. Il n’y a donc aucun signe distinctif pour indiquer que l’on arrive à la fin de l’extrait tant que l’on n’a pas rencontré le prochain :H10:HUB101 (qui est le début de l’extrait suivant)


    Dans l’exemple ci-dessous, on peut donc voir 3 extraits.


    :H10:HUB101
    :H15:V0002
    :H20:H05700809
    :H30:080226134
    :H61:
    :H65:CH03A
    :21:VSLA120080200106
    7D:SETE GENRLE

    F-800 miens
    :9:/F630003021100005825
    F 800 Saint uveur

    :H10:HUB101
    :H15:V00S
    :H20:H05700810
    :H25:SEEEEE
    :H30:00226134915
    :20:20022600001
    :21R:2022600001
    :50H/0/35655801
    VSL Innational AG
    Amouzoka
    Neuflrasse 11
    302 Bn
    :71A:SHA

    :H10:HUB101
    :H15:V0002
    :H20:H05700811
    :H25:XXXXX
    :H30:00226134915
    :20:20022600001
    u du ember 91




    Je cherche l’expression régulière qui me permettrait de faire une boucle sur chaque extrait du fichier.

    Le principal souci, c’est que je n’arrive pas à faire dire à l’expression régulière quelque chose comme

    « Reconnais l’extrait composé d’une ligne commençant par :H10:HUB101 et ensuite tout jusqu’au prochain :H10:HUB101 »

    La difficulté c’est que le prochain :H10:HUB101 fait partie de l’extrait suivant.

    Je pensais à une expression régulière comme :

    (^:H10:HUB101.*?(?:(?!^:H10:HUB101)))

    Mais cela ne marche pas.

    Auriez-vous une idée ?

    Voici toujours mon programme Perl

    ====================
    #!/usr/bin/perl
    # Effectue une boucle sur chaque extrait HUB101 du fichier filein

    use File::Basename;

    use strict;

    # Initialisation
    my $filein=undef;
    my $fullfilein=undef;
    my $extATrouver=undef;
    my $nbExt=0;

    undef $/;

    $fullfilein = $ARGV[0];

    # Ouverture en lecture du fichier 1 pour connaitre les relevés a récupérer
    open(FILEIN, $fullfilein) or die "Fichier $fullfilein introuvable";

    # lecture du fichier FILEIN
    $filein = <FILEIN> ;
    # Boucle sur chaque extrait HUB101
    while ( $filein =~ m/(^:H10:HUB101.*?(?:(?!^:H10:HUB101)))/smg) {

    $extATrouver = $1;

    $nbExt++;

    print "\nExtrait N° : ".$nbExt."\n";
    print $extATrouver;

    }

    close(FILEIN) or die "Fermeture impossible $fullfilein: $!";;
    print "Fin"."\n";

  2. #2
    Membre chevronné Avatar de iblis
    Inscrit en
    Janvier 2007
    Messages
    510
    Détails du profil
    Informations personnelles :
    Âge : 59

    Informations forums :
    Inscription : Janvier 2007
    Messages : 510
    Par défaut
    Tu peux peut être simplement lire ton fichier séquentiellement et gérer avec une variable d'état pour savoir où tu es.

    Je ne sais pas trop sous quelle forme tu veux avoir le résultat mais voilà (pour le cas le plus général) une idée pour récupérer les données dans un tableau de tableau (chaque élément est un enregistrement contenant la liste des champs).

    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
    #!/usr/bin/perl -w
    use strict;
    #use Data::Dumper;
     
    my $mark = ':H10:HUB101';
     
    my $fields;
    my $lines = undef;
     
    while (<>) {
        chomp;
        my $inside = not m/^$mark$/ .. m/^$mark$/;
    #    print "$inside\t$_\n";
        if ($inside) {
            push @$lines, $_;
        }
        else {
            push @$fields, $lines if defined $lines;
            $lines = undef;
        }
     
    }
     
    #print Dumper($fields);
    J'ai mis des print en commentaire pour que tu vois ce qui se passe.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 36
    Par défaut
    Bonjour,

    Merci de t'être penché sur mon problème.
    Oui, je pourrais procéder comme cela

    En fait, l'exemple que j'ai montré est un cas simple.

    En réalité, chaque fichier en entrée peut contenir un grand nombre d'extraits

    Je cherche à retrouver parmi ces milliers d'extraits 2 ou 3 extraits particuliers et à les comparer de façon ultraprécise aux 2 ou 3 autres extraits générés par une autre chaine de traitement.

    C'est pour faire de la non régression. Je prefererai donc éviter tout ce qui modifie le texte d'origine (comme chomp)

    Mais c'est sur que si je n'arrive à faire marcher l'expression régulière, je ferais avec ta solution. Par contre, j'ai l'impression que la chaine :H10:HUB101 est zappée à chaque fois ?

    Au fait, entre une lecture séquentielle et une expression régulière, au niveau des perfs, est-ce du pareil au même ?

    Mais bon, pour ma culture, si je peux savoir ce qui cloche dans l'expression régulière ? Et d'une manière générale, comment faire fonctionner une expression avec lookahead ?

  4. #4
    Expert confirmé
    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
    Par défaut
    Citation Envoyé par david2109 Voir le message
    Au fait, entre une lecture séquentielle et une expression régulière, au niveau des perfs, est-ce du pareil au même ?
    Non, globalement, la lecture ligne à ligne est légèrement moins performante puisqu'on doit effectuer le découpage du fichier. Jusqu'à ce qu'on tombe sur un vrai gros fichier, alors la lecture ligne à ligne sera plus performante parce qu'elle évitera d'avoir à allouer et à maintenir une énorme quantité de donnée en mémoire.
    La lecture ligne à ligne devrait presque toujours être préférée pour les fichier texte, si elle est possible. La différence de performance n'est pas très significative et le programme est plus robuste.

    Par ailleurs, tu n'utilises pas le bon lookahead, (?!regex) est le lookahead négatif, qui réussit lorsque regex ne matche pas à l'emplacement du lookahead. Combine ça avec ton quantificateur paresseux et il suffit à ta regex de matcher ":H10:HUB101", puis de ne rien matcher avec ".*?", puis de vérifier qu'il n'y a effectivement pas ":H10:HUB101" après pour réussir...
    Tu aurais dû utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    m/(^:H10:HUB101.*?)(?=^:H10:HUB101)/smg
    D'un autre côté, c'est franchement inefficace comme façon de faire, un simple "split m/^:H10:HUB101/sm" aurait suffit et aurait été bien plus performant...

    --
    Jedaï

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2008
    Messages
    39
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Février 2008
    Messages : 39
    Par défaut
    Tu peux simplement utiliser ta chaine comme séparateur de ligne non?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $/ = ':H10:HUB101';
     
    while(<>){
    ...
    }

  6. #6
    Expert confirmé
    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
    Par défaut
    Citation Envoyé par PerlPicker Voir le message
    Tu peux simplement utiliser ta chaine comme séparateur de ligne non?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $/ = ':H10:HUB101';
     
    while(<>){
    ...
    }
    Effectivement, c'est la solution la plus élégante !
    (j'utiliserais plutôt "\n:H10:HUB101" par contre)

    --
    Jedaï

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

Discussions similaires

  1. Synthèse et reconnaissance vocale avec speech sdk 5.1
    Par katebe dans le forum Windows Forms
    Réponses: 1
    Dernier message: 07/03/2009, 16h34
  2. Réponses: 2
    Dernier message: 18/09/2008, 10h49
  3. Réponses: 3
    Dernier message: 16/03/2006, 16h44
  4. [Regex] Vérifier un texte avec accents
    Par supermanu dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 09/10/2005, 15h29

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