Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Casse-tête: évaluation d'expression

4 réponses
Avatar
Yves Martin
Bonjour,

J'ai h=E9sit=E9 =E0 poser la question ici avant de passer un bon moment ave=
c
un coll=E8gue pour comprendre le comportement d'un bout de code (mal)
g=E9n=E9r=E9. Et comme ce n'est pas banal comme probl=E8me, je le poste qua=
nd
m=EAme.

Voici le code mal g=E9n=E9r=E9 - le "if" provient d'une recopie d'expressio=
n
r=E9guli=E8re depuis un fichier de configuration dans un "eval":

my $line=3D'2007/11/14 12:00:20 066 ERROR Exception caught';

if ( $line =3D~ m/^..../../.. 05:3 .*ERROR/ ){
print "Match !!\n";
exit 1;
}

L'erreur provient de l'oubli des escapes sur les "/" dans le fichier de
configuration des expressions r=E9guli=E8res.

Mais on s'est demand=E9 pourquoi ce code compilait et =E9tait valide (il y =
a
quand m=EAme un warning =E0 l'=E9valuation) et aussi pourquoi la condition =
du
"if" =E9tait toujours vrai...

D=E9sol=E9 mais il n'y a rien =E0 gagner =E0 ce jeu concours ;)
--=20
Yves Martin

4 réponses

Avatar
kurtz le pirate
In article ,
Yves Martin wrote:

Bonjour,

J'ai hésité à poser la question ici avant de passer un bon moment avec
un collègue pour comprendre le comportement d'un bout de code (mal)
généré. Et comme ce n'est pas banal comme problème, je le poste quand
même.

Voici le code mal généré - le "if" provient d'une recopie d'expression
régulière depuis un fichier de configuration dans un "eval":

my $line='2007/11/14 12:00:20 066 ERROR Exception caught';

if ( $line =~ m/^..../../.. 05:3 .*ERROR/ ){
print "Match !!n";
exit 1;
}

L'erreur provient de l'oubli des escapes sur les "/" dans le fichier de
configuration des expressions régulières.

Mais on s'est demandé pourquoi ce code compilait et était valide (il y a
quand même un warning à l'évaluation) et aussi pourquoi la condition du
"if" était toujours vrai...


oui, un :
use of uninitialized value in pattern match (m//) at ... line 8.

le test donne :
$& -> "2007"
$' -> "/11/14 12:00:20 066 ERROR Exception caught"

je pense (mais je suis très loin d'être un expert) que lors de la
recherche, perl trouve la concordance de ^.... avec 2007 (d'ailleurs la
valeur de $MATCH et bien "2007" et sort car le / suivant est pour lui la
fin de l'expression m// puisqu(il n'est bien sûr pas protégé !

le reste <../.. 05:3 .*ERROR> génère l'erreur.


il faudrait utiliser les Q...E pour "protéger" la chaine.
voir perlfaq perlre


:)
--
klp

Avatar
Jean-Baptiste Mazon
In article ,
Yves Martin wrote:

L'erreur provient de l'oubli des escapes sur les "/" dans le fichier de
configuration des expressions régulières.



Plutôt qu'échapper les `/' on peut aussi changer de délimiteur.
Lisibilité à débattre (dans les deux cas). Les goûts et les
couleurs...

kurtz le pirate writes:
je pense (mais je suis très loin d'être un expert) que lors de la
recherche, perl trouve la concordance de ^.... avec 2007 (d'ailleurs la
valeur de $MATCH et bien "2007" et sort car le / suivant est pour lui la
fin de l'expression m// puisqu(il n'est bien sûr pas protégé !

le reste <../.. 05:3 .*ERROR> génère l'erreur.


Oui et non.
Essaye de définir $_ avant le bloc, et pouf! plus d'erreur ;-)


Avatar
Jerome Quelin
Yves Martin wrote:
my $line='2007/11/14 12:00:20 066 ERROR Exception caught';

if ( $line =~ m/^..../../.. 05:3 .*ERROR/ ){
print "Match !!n";
exit 1;
}
[...]

Mais on s'est demandé pourquoi ce code compilait et était valide (il y a
quand même un warning à l'évaluation) et aussi pourquoi la condition du
"if" était toujours vrai...


parce que .. est un opérateur valide en perl : c'est l'opérateur flip flop
dans une condition. sauf que le flip-flop n'a aucune valeur pratique dans
un if, c'est utilisé pour des boucles. perldoc perlop pour plus d'infos sur
cet opérateur.

ton expression est donc parsée comme :
if ( $line =~ m/^..../ .. /.. 05:3 .*ERROR/ ){

et comme $line a bien 4 caractères, ça matche et ton bloc conditionnel est
exécuté.

c'est donc un hasard qui fait que tu matchais 2 caractères (..) au milieu.
note que avec 3 points (...) ça aurait marché aussi (autre forme du
flip-flop), mais au delà (4 points ....) cela ne marche plus.

cdlt,
jérôme
--


Avatar
jl_morel
Dans l'article , a dit...

J'ai hésité à poser la question ici avant de passer un bon moment ave >c
un collègue pour comprendre le comportement d'un bout de code (mal)
généré. Et comme ce n'est pas banal comme problème, je le poste qua >nd
même.

Voici le code mal généré - le "if" provient d'une recopie d'expressio >n
régulière depuis un fichier de configuration dans un "eval":

my $line='2007/11/14 12:00:20 066 ERROR Exception caught';

if ( $line =~ m/^..../../.. 05:3 .*ERROR/ ){
print "Match !!n";
exit 1;
}

L'erreur provient de l'oubli des escapes sur les "/" dans le fichier de
configuration des expressions régulières.

Mais on s'est demandé pourquoi ce code compilait et était valide (il y >a
quand même un warning à l'évaluation) et aussi pourquoi la condition >du
"if" était toujours vrai...



Pour compléter ce qui a déjà été dit, on peut utiliser le debugger de
regexp intégré à perl. Il suffit d'ajouter
use re 'debug';
au debut du script.
Avec votre bout de code, on voit que perl compile deux regexps :
( pour les détails voir perldebguts :
http://www.bribes.org/perl/docfr/perldebguts.html#LD64431B2 )

Compiling REx `^....'
size 6 Got 52 bytes for offset annotations.
first at 2
1: BOL(2)
2: REG_ANY(3)
3: REG_ANY(4)
4: REG_ANY(5)
5: REG_ANY(6)
6: END(0)
anchored(BOL) minlen 4
Offsets: [6]
1[1] 2[1] 3[1] 4[1] 5[1] 6[0]
Compiling REx `.. 05:3 .*ERROR'
size 11 Got 92 bytes for offset annotations.
first at 1
1: REG_ANY(2)
2: REG_ANY(3)
3: EXACT < 05:3 >(6)
6: STAR(8)
7: REG_ANY(0)
8: EXACT <ERROR>(11)
11: END(0)
anchored ` 05:3 ' at 2 floating `ERROR' at 8..2147483647 (checking anchored)
minlen 13
Offsets: [11]
1[1] 2[1] 3[6] 0[0] 0[0] 10[1] 9[1] 11[5] 0[0] 0[0] 16[0]
Matching REx `^....' against `2007/11/14 12:00:20 066 ERROR Exception caught'
Setting an EVAL scope, savestack=5
0 <> <2007/11/14 1> | 1: BOL
0 <> <2007/11/14 1> | 2: REG_ANY
1 <2> <007/11/14 1> | 3: REG_ANY
2 <20> <07/11/14 1> | 4: REG_ANY
3 <200> <7/11/14 1> | 5: REG_ANY
4 <2007> </11/14 1> | 6: END
Match successful!
Use of uninitialized value in pattern match (m//) at F:tmp_perlREGEXP~4.PL
line 8.
Freeing REx: `"^...."'
Freeing REx: `".. 05:3 .*ERROR"'
Match !!

HTH
--
J-L.M.
http://www.bribes.org/perl