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 :

Récupération d'un nombre variable de champs à l'aide d'une regex


Sujet :

Langage Perl

  1. #1
    Membre habitué
    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
    Points : 138
    Points
    138
    Par défaut Récupération d'un nombre variable de champs à l'aide d'une regex
    Bonjour,

    je recevais d'un prestataire des fichiers plats avec des champs pouvant contenir un nom de variable à traiter dans la suite du programme, exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    LISTE_REGLEMENT_${XXXX}.csv
    Avec le code suivant, je pouvais récupérer "XXXX" dans $var :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if ( $str =~ /^(.*)\$\{(.+)\}(.*)$/ ) {
        ( $prf, $var, $suf ) = ( $1, $2, $3);
    }
    Maintenant ces champs peuvent contenir n variables, dela forme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    'LISTE_REGLEMENT_${AA}${MM}.csv
    pour récupérer AA et MM, ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    'LISTE_REGLEMENT_${AA}${MM}-phase1-${XXXX}.csv
    pour récupérer AA, MM et XXXX

    Est-il possible de résoudre cette demande en utilisant toujours les regex ?

  2. #2
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 211
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 211
    Points : 8 316
    Points
    8 316
    Billets dans le blog
    52
    Par défaut
    Il me semble plus prudent de faire du split simple...
    En premier sur $
    Qui te donnera :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {"LISTE_REGLEMENT_","{AA}","{MM}-phase1-","{XXXX}.csv"}
    Tu ne prends pas le premier, car non précédé d'un $.
    Et tu fais de nouveau un split sur les autres avec les caractères de séparation "-" et "." en ne conservant que le début.

    Sauf si tes variable dispose de caractère de séparation du devrait être tranquille.

    Lien vers la doc split Perl:
    http://www.comp.leeds.ac.uk/Perl/split.html

    Cordialement,
    Patrick Kolodziejczyk.
    Si une réponse vous a été utile pensez à
    Si vous avez eu la réponse à votre question, marquez votre discussion
    Pensez aux FAQs et aux tutoriels et cours.

  3. #3
    Membre habitué
    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
    Points : 138
    Points
    138
    Par défaut
    Merci pour ce 1er axe de recherche.

    Je dois préciser que le contenu des champs est variable, ils peuvent du texte libre et de 1 à n variables :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {"LISTE_REGLEMENT_","{AA}","{MM}-phase1-","{XXXX}.csv"}
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ARRETE ${YYYY} du traitement ${ZZ} integré dans archive${RR}${ZZ}
    Je dois pouvoir identifier toutes les chaînes intégrées dans les motifs ${} pour la suite du traitement

  4. #4
    Modérateur
    Avatar de kolodz
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    2 211
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 211
    Points : 8 316
    Points
    8 316
    Billets dans le blog
    52
    Par défaut
    A ce moment là faut poser des règles simple :
    Pas de $ dans une variable.
    Ainsi qu'une liste de délimiteur donnée : Espace, point...

    Il faut que tu ai un moyen simple de déterminer si tu prend en compte "-phase1" ou " integré dans archive"

    Si l'espace est un délimiteur, alors non. Sinon, c'est à prendre en compte de manière systématique.

    Les règles à appliquées doivent être simple systématique et réalisable avec un papier et un stylo.

    Cordialement,
    Patrick Kolodziejczyk.
    Si une réponse vous a été utile pensez à
    Si vous avez eu la réponse à votre question, marquez votre discussion
    Pensez aux FAQs et aux tutoriels et cours.

  5. #5
    Membre habitué
    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
    Points : 138
    Points
    138
    Par défaut
    J'ai pris le papier et le stylo
    La règle est : identifier dans un champ variable toutes les valeurs matchant le motif ${.+}, quelles que soient leur position.

    J'ai trouvé une solution (de contournement ? ) qui fonctionne.
    Je me demande maintenant s'il n'y a pas une solution plus simple avec une regex et sans la structure while.

    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
     
    #!/usr/bin/perl -w
    use strict;
     
    my $str = 'LISTE_REGLEMENT_${AA}${MM}-phase1-${XXXX}.csvr';
    my @vars;
     
    while ( $str =~ /\$\{(.+?)\}/ ) { 
        my $var = $1; 
        $str =~ s/\$\{$var\}//;
        push(@vars, $var);
    }
     
    print join ("-", @vars);
    print "\n";
    Résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $ ./test_regex2.pl 
    AA-MM-XXXX

  6. #6
    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
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bonjour,

    Cette expression régulière en contexte de liste devrait le faire:
    Un exemple illustré sous le debugger:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
      DB<1>  $str = 'LISTE_REGLEMENT_${AA}${MM}-phase1-${XXXX}.csvr';
     
      DB<2>  @vars = $str =~ /\$\{([^}]+)\}/g;
     
      DB<3> x \@vars
    0  ARRAY(0x600500d38)
       0  'AA'
       1  'MM'
       2  'XXXX'
    A ta disposition pour te fournir des explications supplémentaires si tu ne comprends pas tout.

  7. #7
    Membre habitué
    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
    Points : 138
    Points
    138
    Par défaut
    J'ai remplace avec succès ma structure while par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ( @vars ) = ( $str =~ /\$\{([^}]+)\}/g );
    C'est ce que je cherchais à construire.
    Par contre, bien qu'entrevoyant (de manière nébuleuse) une interprétation de la construction, je lirais avec une très grande attention ton explication

  8. #8
    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
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Alors,
    reconnaît:

    - \$ : un signe $, suivi de:
    - \{ : une accolade ouvrante, suivie de:
    - ( : une parenthèse ouvrante servant uniquement à la capture de ce qui suit jusqu'à la parenthèse fermante
    - [^}]+ : un ou plusieurs caractères quelconques autres qu'une accolade fermante ( "[^}]" est une classe de caractère négative, à noter qu'il n'est pas nécessaire de précéder l'accolade d'un antislash dans une classe de caractère), suivi de
    - ) : la parenthèse fermante de la capture, suivie de
    - \} : une accolage fermante.

    Le modificateur /g demande à la regex de faire la reconnaissance du motif autant de fois que possible et, en contexte de liste, la regex renvoie une liste de chaînes reconnues et capturées qu'il suffit d'affecter au tableau @vars.

    A noter qu'il est inutile de mettre @vars entre parenthèses, c'est un tableau, il suffit à fournir le contexte de liste (mais ça ne gêne pas).

    De même, l'opérateur d'affectation "=" ayant une précédence bien plus faible que l'opérateur de liaison "=~", les parenthèses ne sont pas nécessaires autour de l'expression "$str =~ /\$\{([^}]+)\}/g ", il est garanti que cette expression sera évaluée avant l'affectation, donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    my @vars = $str =~ /\$\{([^}]+)\}/g;
    sans ces parenthèses suffit, mais tu peux tout à fait mettre ces parenthèses si tu trouves que c'est plus clair ainsi.

  9. #9
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Bonjour,

    Cette expression régulière suffit amplement :
    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
    #!/usr/bin/perl
    use warnings;
    use strict;
    use Data::Dumper;
     
    my $chaine = <<'TEST';
    LISTE_REGLEMENT_${AA}${MM}-phase1-${XXXX}.csvr
    ARRETE ${YYYY} du traitement ${ZZ} integré dans archive${RR}${ZZ}
    $test et autre champ{} - ${AUTRE_VARIABLE}
    TEST
    my @variables = $chaine =~ m{
        \$     # distinction de la variable
        \{     # délimitation de la variable
        (.+?)  # Nom de la variable capturé
        \}     # Fin délimitation de la variable
    }msgx;
    On obtient bien
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $VAR1 = [
              'AA',
              'MM',
              'XXXX',
              'YYYY',
              'ZZ',
              'RR',
              'ZZ',
              'AUTRE_VARIABLE'
            ];

  10. #10
    Membre habitué
    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
    Points : 138
    Points
    138
    Par défaut
    J'utilise déjà beaucoup les expressions rationnelles, mais je n'avais jamais été confronté à cette problématique.

    Dans ma structure while j'utilise un quantificateur non gourmand et cela fonctionne, par contre je me doutais qu'il y avait plus simple à faire.
    Je ne savais pas qu'on pouvait récupérer dans un tableau toutes les correspondances en une seule expression.

    Un grand .

  11. #11
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par ptonnerre Voir le message
    Je ne savais pas qu'on pouvait récupérer dans un tableau toutes les correspondances en une seule expression.
    Tu peux même l'inclure dans une expression "booléenne" ou dans une boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    foreach my $file ($file_list =~ /file=(\w+);/g) {
      # ...
    }
    if (my ($file, $title) = $header =~ /file=(\w+);.*title=(\w+);/) {
      # ...
    }
    if (my @files = $file_list =~ /file=(\w+);/g) {
      # ...
    }
    Certes, les affectations dans les conditions de if sont rarement recommandées dans les règles de codage, mais en ici, cela permet d'être à la fois concis tout en restant clair est peu ambiguë par rapport à un test ==.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

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

Discussions similaires

  1. [AC-2003] Comment concaténer un nombre variable de champs?
    Par Chris@Xerox dans le forum Requêtes et SQL.
    Réponses: 6
    Dernier message: 05/10/2010, 10h56
  2. [AC-2007] Validation d'un champ à l'aide d'une douchette
    Par redwarf dans le forum VBA Access
    Réponses: 26
    Dernier message: 09/10/2009, 13h05
  3. Réponses: 4
    Dernier message: 01/05/2009, 15h41
  4. Réponses: 3
    Dernier message: 13/03/2008, 14h28
  5. Masquer un champs à l'aide d'une checkbox
    Par Jumano dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 19/03/2007, 16h15

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