[Perl] Où $1 est-il capturé?

Jean ponder.stibbons at orange.fr
Ven 1 Avr 07:27:40 CEST 2016


Le jeudi 31 mars 2016 à 09:12 +0200, Sebastien Moretti a écrit :
> > C'est pour cette raison qu'il faut vérifier que la regex a bien été
> > reconnue avant d'utiliser $1.
> 
> Tu prêches un converti!
> 
> > Exécute le code qui suit pour illustration. Le premier bloc est
> > incorrect car $1 conserve sa valeur tant qu'une nouvelle correspondance
> > n'est pas réussie (auquel cas $1 est mis à jour).
> 
> Je pensais quand même qu'il y avait une limite, un scope, à ça.
> Mais non semble-t-il.
> Potentiellement très dangereux.
> 
$1 est une variable *globale* et "use strict" accepte cette variable
globale (ainsi que toutes les variables spéciales comme $! ou $/).
Ce n'est pas la peine de chercher plus loin.

Adopter de bonnes pratiques comme "use strict" et la déclaration
systématique de variables avec "my" est une bonne chose, mais il
ne faut pas oublier qu'il y a quelque chose à côté.
Les variables globales sont peut-être très dangereuses, mais parfois
elles se révèlent très utiles. Cf l'anecdote récemment diffusée :
http://thedailywtf.com/articles/a-meaty-problem
(c'est du Java et de l'anglais, désolé).

Pour capturer des sous-chaînes, j'utilise la syntaxe :

  my $line = "  Zone:  2.50h East of Greenwich"
  my ($delta, $hemi) = $line =~ /^\s*Zone:
                                  \s+(\d+(?:\.\d+)?)h # delta hours
                                  \s+(East|West)      # hemisphere
                                  \s+of\s+Greenwich/x;

Et si ça foire (par exemple, écrire "Greenwich" dans la chaîne et
"Greenwwich" dans l'expression régulière, exemple vécu hier soir)
j'obtiens un message "use of undefined value ...". Mais l'avantage
est que les captures se font dans des variables *lexicales*
et que l'on sait rapidement s'il y a un échec.

Il y a aussi les captures nommées directement à l'intérieur
de l'expression régulière :

  $line =~ /^\s*Zone:
             \s+(?<delta>\d+(?:\.\d+)?)h # delta hours
             \s+(?<hemi>East|West)      # hemisphere
             \s+of\s+Greenwich/x;

(Le code n'est pas  testé, je n'ai pas encore complètement intégré
les nouvelles fonctionnalités de Perl 5.10.)

Dans ton cas, il s'agit d'un s/// et non pas d'un m//. Je ne sais
pas si les deux méthodes conviennent au s///.

En espérant t'avoir été utile,

Jean



Plus d'informations sur la liste de diffusion Perl