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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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.

+ 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