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 :

REGEXP - réinitialiser $&, $1, etc.


Sujet :

Langage Perl

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 66
    Points : 60
    Points
    60
    Par défaut REGEXP - réinitialiser $&, $1, etc.
    Et voici un problème qui me fait m'arracher les cheveux de la tête :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    @strings = ... #un tableau contenant des chaînes de caractères
     
    $nb_occurences = 0;
    for(@strings) {
      # Recherche sur la chaîne courante
      $_ =~ /.../;
      if ($& ne "") {$nb_occurences++);
    }
    Supposons que la 1ère chaîne contient ce qu'on recherche. La variable $&
    est donc significative. Le problème est que $& restera inchangée MÊME en
    cas de recherche infructueuse par la suite (au lieu d'être remise à zéro) !!!!

    On se retrouve donc avec une valeur erronée pour $nb_occurences.
    Comment contourner ce problème ATROCE (bien que sans doute très connu)
    et qui me fait penser que PERL est un langage aussi détestable que je le craignais.

  2. #2
    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 Mat_F
    On se retrouve donc avec une valeur erronée pour $nb_occurences.
    Comment contourner ce problème ATROCE (bien que sans doute très connu)
    et qui me fait penser que PERL est un langage aussi détestable que je le craignais.
    Pitié pas de remarque comme ça après 4 jours d'apprentissage et sur un point complètement erroné...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    my @strings = ... #un tableau contenant des chaînes de caractères
     
    my $nb_occurences = 0;
    foreach (@strings) {
      # Recherche sur la chaîne courante
      $nb_occurences++ if m/.../;
    }
    Si la recherche (ou pas mal d'autres opérations) se fait sur $_ il est inutile de l'expliciter. Si tu veux vraiment être explicite, alors tu n'utilises surtout pas $_ (nom de variable laid et ne donnant aucune information sur le contenu) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    my @strings = ... #un tableau contenant des chaînes de caractères
     
    my $nb_occurences = 0;
    foreach my $string (@strings) {
      # Recherche sur la chaîne courante
      $nb_occurences++ if $string =~ m/.../;
    }
    Il est recommandé de ne pas utiliser $& et ses cousins $` et $', car leur usage dans un script ralentit globalement le moteur de regex, à la place utilise directement $1, $2, etc... et éventuellement @+ et @-, mais tu n'en auras normalement pas besoin, si tu conçois bien ta regex. Le problème de réinitialiser $1 et compagnie ne se pose pas vraiment car tu ne devrais pas accéder à ces variables si ton match n'a pas été réussi.

    Pour un Perl (Perl est le langage et perl l'interpréteur, PERL est une erreur car Perl n'est pas un acronyme) plus propre, rajoute "use strict;" au début de ton script pour être obligé de déclarer tes variables (avec my() comme je l'ai fait plus haut) et ainsi éviter pas mal de chausse-trappes.

    Et n'hésite pas à poser d'autres questions ici.
    Consulte également notre FAQ.

    Une façon un peu plus idiomatique de faire ce que tu veux est :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    my @strings = ... ;
    my $nb_occurences = grep { m/.../ } @strings;
    --
    Jedaï

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 66
    Points : 60
    Points
    60
    Par défaut
    Jedai, désolé pour mes remarques excessives, je me suis un peu laissé emporter. A part ça, ta réponse me laisse un peu perplexe et ne répond pas vraiment à ma question.
    Je comprends que tu aies envie de faire passer ta manière de voire les choses (Perl et non PERL, une strict, etc.) Par contre, je pense que ces considérations devraient être mentionnées de façon annexe, une fois le problème précis traité, en l'occurence l'initialisation de la variable $& dans une regexp.

    Je pense néanmoins avoir compris mon erreur, voici donc le code modifié que je pense être correct :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @strings = ... #un tableau contenant des chaînes de caractères
    
    $nb_occurences = 0;
    for(@strings) {
      # Recherche sur la chaîne courante
      if($_ =~ /.../) {$nb_occurences++); # "bonne" approche
      if ($& ne "") {$nb_occurences++); # mauvaise approche
    }
    Je n'avais simplement pas compris que la recherche pouvait renvoyer true/false.

    Sinon, je n'ai pas compris la remarque sur $_ et le fait de "l'expliciter". Jedi, veux tu dire que les lignes de code ci-dessous sont équivalentes (dans le contexte du code précédent) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if ($_ =~ /.../) {...}
    if (/.../) {...}
    Si oui, que devient l'opérateur =~ ? Faut-il à ce moment utiliser m/.../ au lieu de simplement /.../ ?

    Une dernière chose suscite mon incompréhension dans le code publié dans ton message :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    $nb_occurences++ if $string =~ m/.../;
    if($string =~ m/.../) {$nb_occurences++;}
    # les 2 lignes ci-dessus sont-elles équivalentes ?

  4. #4
    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 Mat_F
    Jedai, désolé pour mes remarques excessives, je me suis un peu laissé emporter. A part ça, ta réponse me laisse un peu perplexe et ne répond pas vraiment à ma question.
    Je comprends que tu aies envie de faire passer ta manière de voire les choses (Perl et non PERL, une strict, etc.) Par contre, je pense que ces considérations devraient être mentionnées de façon annexe, une fois le problème précis traité, en l'occurence l'initialisation de la variable $& dans une regexp.
    Il me semblait pourtant clair que ma première réponse montrait qu'il ne fallait pas tester les variables spéciales pour savoir si une regex avait réussi, mais directement tester la regex, c'était la seule vraie réponse... Je ne réponds pas "directement" à ta question puisque comme je te l'ai dit, elle ne se pose pas, sauf s'il y a un défaut de logique dans ton programme : ça n'a pas de sens de travailler avec les variables spéciales d'un match qui a échoué.

    Les "use strict;" et autre PERL ne sont mentionnés qu'à la fin de mon message, tu aurais voulu que j'écrive un gros titre "Annexe" avant pour que ce soit plus clair ?

    $_ est la variable "sujet" de Perl, autrement dit, elle est le sujet par défaut de la plupart des opérations agissant sur un scalaire (comme chomp(), print(), split(), les regexs m// et s///, etc). Perl a été écrit par un linguiste, et ça se sent dans un certain nombre de ses constructions.

    Quant à ta dernière question, peut-être que si tu jetais un coup d'oeil à notre FAQ ou à la documentation Perl (très riche, tu as des liens vers une traduction en français dans les sujets "[Important]" du forum), tu aurais la réponse à ta question (sans parler du fait que l'avantage d'un langage dynamique c'est aussi qu'on puisse tester ses suppositions en un instant plutôt que d'attendre plusieurs heures une réponse sur un forum)... Bien évidemment le fait que tu poses la question semble impliquer que tu ne me fais pas du tout confiance pour te donner une syntaxe qui marche.

    --
    Jedaï

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juillet 2006
    Messages : 66
    Points : 60
    Points
    60
    Par défaut
    Citation Envoyé par Jedai
    Il me semblait pourtant clair que ma première réponse montrait qu'il ne fallait pas tester les variables spéciales pour savoir si une regex avait réussi, mais directement tester la regex, c'était la seule vraie réponse... Je ne réponds pas "directement" à ta question puisque comme je te l'ai dit, elle ne se pose pas, sauf s'il y a un défaut de logique dans ton programme : ça n'a pas de sens de travailler avec les variables spéciales d'un match qui a échoué.
    Bref, il est toujours plus facile de faire la morale (et des suppositions) que de répondre clairement à une question.

  6. #6
    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 Mat_F
    Bref, il est toujours plus facile de faire la morale (et des suppositions) que de répondre clairement à une question.
    En quoi suis je en train de te "faire la morale" ? Je réponds à ta question en supposant que tu es doté d'une intelligence normale, et que je n'ai pas besoin d'être explicite ou de te fournir un mode d'emploi... Et a priori ma réponse n'était pas si difficile à comprendre puisque tu as parfaitement saisi ce que je te disais, sur tous les points ! Si tu veux un mode d'emploi, lit la documentation, jette un coup d'oeil à la FAQ, comme je te l'ai déjà suggéré c'est là que tu apprendras le plus de choses rapidement si tu es en train d'apprendre le langage.
    La phrase que tu cites est tout sauf de la morale : j'explicite pourquoi ta question ne se pose pas en tant que telle, la "réponse" à ta question implicite (comment vérifier si un match a réussi) étant d'esquiver le problème avec une construction plus robuste (même quand le match a réussi $& n'est pas forcément différent de "" avec certaines regexs alors que if( m// ) marchera toujours).

    --
    Jedaï

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

Discussions similaires

  1. Documentation gratuite sur l'API Windows, COM, DCOM, OLE, etc.
    Par Community Management dans le forum Windows
    Réponses: 1
    Dernier message: 16/11/2006, 15h28
  2. Librairie OO et portable pour RegExp, Thread, Sockets, etc..
    Par Swoög dans le forum Bibliothèques
    Réponses: 29
    Dernier message: 27/05/2006, 12h29
  3. [Choix] SGDB pour Entreprise : coût, efficacité, etc.
    Par grassat dans le forum Décisions SGBD
    Réponses: 4
    Dernier message: 15/06/2002, 08h52

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