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 :

Portée des variables perl


Sujet :

Langage Perl

  1. #1
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut Portée des variables perl
    Bonjour à tous,

    Je ne sais pas comment intituler le sujet, puisque je ne sais pas vraiment pourquoi j'ai le comportement que je vais décrire...

    Voilà le bout de code qui me pose problème:

    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
    use strict;
     
    do_it("263;160;507;410");
    do_it("263;160;507;410");
     
    sub do_it
    {
        my ($p)=@_;
        print "Entering do_it : \"$p\"\n";
        my ($x1, $x2, $y1, $y2);
        $p=~/^([^;]*)(?{ $x1 = $^N});([^;]*)(?{ $y1 = $^N});([^;]*)(?{ $x2 = $^N});(.*)(?{ $y2 = $^N})$/;
        print "x1=$x1, y1=$y1, x2=$x2, y2=$y2\n";
        print "Leaving do_it\n";
    }
    __END__

    L'objectif de cette fonction est d'extraire d'une chaine de caractères les coordonnées de 2 points, P1(x1,y1) et P2(x2,y2). La chaine de caractère se présente sous cette forme : "x1;y1;x2;y2"

    J'ai écrit ce script pour le faire tourner sous HP-UX, perl -v = 5.8.2


    Le problème que je rencontre, c'est que la première fois que j'appel cette fonction, l'extraction se passe bien, et la fois suivante, rien n'est extrait... Et pourtant si la chaine match une première fois, elle n'a aucune raison de ne pas matcher une autre fois...

    Le problème, est, je pense sur la ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $p=~/^([^;]*)(?{ $x1 = $^N});([^;]*)(?{ $y1 = $^N});([^;]*)(?{ $x2 = $^N});(.*)(?{ $y2 = $^N})$/;
    et je pense que ca concerne la portée des variables, parceque si je déplace la ligne my ($x1, $x2, $y1, $y2); juste en dessous du use strict; (donc en dehors de la fonction), alors ca fonctionne parfaitement ... mais ce n'est pas propre.

    Je peux aussi ré-écrire l'expression sous une autre forme (par exemple):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ($x1, $y1, $x2, $y2) = ($p=~/^([^;]*);([^;]*);([^;]*);(.*)$/);
    Et c'est une bonne solution puisque ca résoud mon problème...


    Mais j'aimerais vraiment savoir pourquoi le première expression ne fonctionne pas ? Avez vous des idées ?

    Merci pour vos réponses,
    Lilian.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut J'allais oublier...
    Voici le résultat d'execution:

    $ perl ./test.pl
    Entering
    x1=263, y1=160, x2=507, y2=410
    Leaving
    Entering
    x1=, y1=, x2=, y2=
    Leaving
    $
    Et avec l'autre forme d'expression:
    $ perl ./test.pl
    Entering
    x1=263, y1=160, x2=507, y2=410
    Leaving
    Entering
    x1=263, y1=160, x2=507, y2=410
    Leaving
    $

  3. #3
    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 : 59
    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
    Par défaut
    Etrange effectivement que la localisation "my" des variables s'étende différemment entre le premier appel et les suivant : dans le premier appel, l'étendue s'applique au contenu de la regexp, alors que par la suite, elle ne s'y étend plus (en tout, c'est ce qu'il y parait).

    En affichant $x1 dans la regexp, on s'aperçoit qu'il est bien mis à jour, mais semble-t-il de manière locale, puisqu'il ne subsiste plus après être sorti de la regexp :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $p=~/^([^;]*)(?{ $x1 = $^N ; print "x1:$x1\n"; });([^;]*)(?{ $y1 = $^N});([^;]*)(?{ $x2 = $^N});(.*)(?{ $y2 = $^N})$/;
    En déclarant les variables $x1, $y1, $x2, $y2 en our(), l'expression régulière fonctionne correctement.

    Cela dit, l'écriture
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my ($x1, $y1, $x2, $y2) = $p^=~ /^([^;]*);([^;]*);([^;]*);(.*)$//;
    est :
    - nettement plus lisible et maintenable,
    - sans effet de bord (comme avec $1, $2, ...),
    - défini localement les variables affectées.

  4. #4
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    Merci Philou pour cette réponse rapide,

    Je suis évidement d'accord avec ta dernière remarque concernant la lisibilité et la maintenabilité, et c'est pourquoi c'est la solution que j'ai adopté.

    our() semble être une bonne piste pour comprendre... (mais je ne suis pas un grand fan des variables globales)

    Je me demande si la portée des variables ne change pas dans le cas d'une expression comme celle-ci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $p=~/^([^;]*)(?{ $x1 = $^N});([^;]*)(?{ $y1 = $^N});([^;]*)(?{ $x2 = $^N});(.*)(?{ $y2 = $^N})$/;
    Est-ce que je ne me retrouverais pas avec 2 $x1,..., après la première execution, et qu'ensuite il ne modifierait que la deuxième instance des variables ?

    Un petit perl -d s'impose....

    Merci encore,
    si j'ai une explication je la posterais.

    Lilian.

  5. #5
    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 : 59
    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
    Par défaut
    Au passage, n'oublie pas d'utiliser la balise [code] (ou l'icône ) pour présenter correctement tes bouts de code

  6. #6
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    Oui merci ! Je me demandais justement comment fait-on pour mettre en évidence du code...

    D'ailleurs un essai

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ($x1, $y1, $x2, $y2) = ($p=~/^([^;]*);([^;]*);([^;]*);(.*)$/);

  7. #7
    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 : 59
    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
    Par défaut
    Je crois que j'ai une explication. Pour comprendre, il faut ajouter l'affichage de la référence à $x1 (à la fois à l'extérieur et à l'intérieur de la regexp) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $p=~/^([^;]*)(?{ print "1:$^N\n";$x1 = $^N;print "&x1:".\$x1."\n";});([^;]*)(?{ $y1 = $^N});([^;]*)(?{ $x2 = $^N});(.*)(?{ $y2 = $^N})$/;
    print "x1=$x1 (&x1:".\$x1."), y1=$y1, x2=$x2, y2=$y2\n";
    Résultat :
    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
    Entering do_it : "263;160;507;410"
    1:263
    &x1:SCALAR(0x10091ce0)
    x1=263 (&x1:SCALAR(0x10091ce0)), y1=160, x2=507, y2=410
    Leaving do_it
    Entering do_it : "264;160;507;410"
    1:264
    &x1:SCALAR(0x10091ce0)
    x1= (&x1:SCALAR(0x100ba4a0)), y1=, x2=, y2=
    Leaving do_it
    Entering do_it : "263;160;507;410"
    1:263
    &x1:SCALAR(0x10091ce0)
    x1= (&x1:SCALAR(0x100ba4a0)), y1=, x2=, y2=
    Leaving do_it
    On s'aperçoit que lors du premier appel, la variable my $x1 est crée, dans un contexte local, et utilisée par la regexp.
    Lors du deuxième appel, comme cette variable est locale à la fonction, elle doit être à nouveau définie, et prend donc une nouvelle référence. Cependant, le moteur d'exécution des regexp a mémorisé lors de l'interprétation de la regexp au premier appel, la référence de la variable $my utilisée lors du premier appel, et sans "ré-interpréter" l'expression régulière, il ne cherchera pas à utiliser la nouvelle référence.
    Pour pallier au problème, il faudrait donc déclarer $x1 en my() à l'extérieur de la fonction : dans ce cas, c'est la même variable qui est utilisée à chaque appel (vérification faite, ça fonctionne).

    Ceci est confirmé par le doc du ?{ ... } (considérée d'ailleurs comme expérimentale) :
    Due to an unfortunate implementation issue, the Perl code
    contained in these blocks is treated as a compile time
    closure
    that can have seemingly bizarre consequences when
    used with lexically scoped variables inside of subroutines or
    loops. There are various workarounds for this, including
    simply using global variables instead. If you are using this
    construct and strange results occur then check for the use of
    lexically scoped variables.

  8. #8
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    Oui merci !!!

    C'est ce que je viens de constater avec le deboggeur perl, et la solution que tu proposes fonctionne effectivement (j'en parle dans mon premier post).

    Ce qui me manquait c'était ton explication extraite de la doc.

    Merci de t'être intéressé à mon problème.
    Je vais le tagger "résolu".

    Bonne journée,
    Lilian.

  9. #9
    Membre chevronné
    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
    Par défaut
    C'est marrant, je suis en train de relire le chapitre consacré à Perl de la deuxième édition de Maîtrise des Expressions Régulières, de Jeffrey Friedl, et je viens juste d'arriver à la section "Un avertissement à propos du code imbriqué et des variables my", concernant précisément le problème dont il est question ici. Amusante coïncidence.

  10. #10
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    C'est vrai aussi que ce n'est pas une limitation bien grave, elle est facile à contournée...

    Encore faut-il savoir que c'est un KPR.

    Mais lorsque l'on tombe dessu, ca fait franchement bizarre...

  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 : 59
    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
    Par défaut
    En même temps, l'usage d'effets de bord dans une expression régulière ne me semble pas conseillée (comme la plupart du temps pour les effets de bord). Surtout que dans ce cas précis, l'opérateur =~ retourne déjà les informations mise à jour dans l'expression ?{ ... }, et il est bien plus "naturel" d'utiliser l'opérateur d'affectation de liste dans ce cas (y compris pour ne récupérer qu'un seul élément).
    Par ailleurs, ça permet aussi de limiter au maximum la portée des variables, ce que l'usage de ?{ ... } n'incite pas à faire.

  12. #12
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    Oui tu as raison dans ce cas précis, mais il faut prendre en considération que le bout de code que j'ai posté n'est que l'isolat d'un programme que j'écris.

    Il se trouvait que je récupérais ma ligne à travers $_ (à partir d'un while) et pas $p.
    J'ai simplifié au maximum le code qui me posait problème pour pouvoir l'exprimer plus facilement.

    Mais dans le fond, je suis d'accord avec toi.

  13. #13
    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 : 59
    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
    Par défaut
    Je ne vois pas, cependant, la justification de l'usage de ?{ ... } pour affecter des variables de parenthèses capturantes (qui ne pourraient pas être réalisées avec la simple affectation). Tu as un exemple ?

  14. #14
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    Je n'ai pas dis que ca ne pouvais pas être réalisé avec une simple affectation ... d'autant plus que c'est la solution que j'ai fini par prendre.

    Mais il faut garder à l'esprit que les déclarations, les opérations d'affectation, coutent en temps. Et que dans certains cas le temps n'est pas à négliger, même si l'on choisit Perl plutot qu'un autre language.

    Et là, je compte les ms... donc je m'oriente vers les solutions les moins couteuses, et c'est vrai, pas toujours propres.

  15. #15
    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 : 59
    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
    Par défaut
    As-tu profilé (perl -dDProff script.pl ; dprofpp) pour voir que l'affectation "en passant" était plus rapide que la post-affectation ?
    J'ai franchement un doute.
    Au passage, si tu traques les ms, utilise le profilage, tu verras là où il convient de travailler en priorité. Bon courage.

  16. #16
    Membre expérimenté
    Homme Profil pro
    Gérant infopsylon
    Inscrit en
    Juin 2010
    Messages
    215
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Gérant infopsylon
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2010
    Messages : 215
    Par défaut
    C'est une excellente idée !

    Comme en plus je suis au bord de la release, ce sera un très bon test.

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

Discussions similaires

  1. include en perl et la portée des variables
    Par lennelei dans le forum Langage
    Réponses: 6
    Dernier message: 02/07/2012, 12h44
  2. [FLASH MX] Portée des variables ???
    Par mic79 dans le forum Flash
    Réponses: 2
    Dernier message: 08/02/2005, 10h21
  3. Portée des variables vbscript vers ASP
    Par Immobilis dans le forum ASP
    Réponses: 3
    Dernier message: 03/11/2004, 10h14
  4. [XSL]Problème de portée des variables
    Par djulesp dans le forum XSL/XSLT/XPATH
    Réponses: 6
    Dernier message: 17/09/2004, 10h34
  5. [Portée] portée des variables
    Par parksto dans le forum Langage
    Réponses: 7
    Dernier message: 09/05/2004, 21h05

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