Yo!

Quelqu'un de moins rouillé que moi au niveau des Regexp PHP saurait-il m'expliquer la différence fondamentale de fonctionnement dans ce code? ...
<?php preg_match_all("@\\\$\{(.+)\}(?:\.([0-9]+))@iU", "\${12.5/100}.2", $evalParams); var_dump($evalParams); // Capture bien le 2 dans le ".2" preg_match_all("@\\\$\{(.+)\}(?:\.([0-9]+))?@iU", "\${12.5/100}.2", $evalParams); var_dump($evalParams); // WTF ?

La présence de l'ungreedy est forcée car ma chaîne d'entrée peut ressembler à ceci:
"Vos sorts de soins directs placent également sur votre cible un bouclier qui absorbe un montant de dégâts égal à ${$m2/12.5}% du montant de points de vie rendus et dure $86273d. Chaque point de Maîtrise augmente le montant absorbé de ${$m2/100}.2% supplémentaires".

On remarque que seul le deuxième ${...} possède un attribut de précision (C'est typiquement du printf("%.02f")), sans l'ungreedy, la regexp fonctionne mais capture toute la moitié de la phrase...

Ça commence à me rendre fou cette affaire, je pense que si c'est impossible je vais tout simplement utiliser deux expressions régulières et basta.
À vue d'œil (mais à confirmer), vu que le ? peut prendre soit 0 soit 1 fois l'élément précédent, en ungreedy il va tenter d'en prendre 0 si c'est possible. Et vu qu'il n'y a plus aucune contrainte après, c'est complètement possible.

Tu devrais pouvoir forcer le 2ème à prendre le .2 en ajoutant un élément derrière. Dans le cas de ton exemple, ajouter un $ derrière devrait marcher. Dans le cas de la phrase que tu veux matcher, j'imagine que tu dois pouvoir ajouter le % ?
Non, le % n'a aucune importance dans la capture, il doit rester affiché dans la chaîne de sortie quand je ferais mes substitutions wink


Pour
"Vos sorts de soins directs placent également sur votre cible un bouclier qui absorbe un montant de dégâts égal à ${$m2/12.5}% du montant de points de vie rendus et dure $86273d. Chaque point de Maîtrise augmente le montant absorbé de ${$m2/100}.2% supplémentaires".
On attend ce genre de résultat:
"Vos sorts de soins directs placent également sur votre cible un bouclier qui absorbe un montant de dégâts égal à 15% du montant de points de vie rendus et dure 15s. Chaque point de Maîtrise augmente le montant absorbé de 2.5% supplémentaires".

La substitution de m1, etde 86273d a lieu plus tard et ne gêne pas outre mesure wink

[EDIT] En outre je viens de constater un autre problème sur ma chaîne d'entrée:ams);avec preg_match_all("@\\\$\{(.+)\}(?:\.([0-9]+))@U", $description, $evalPar
j'obtiens:
array (size=3)
0 =>
array (size=1)
0 => string '${150/12.5}% du montant de points de vie rendus et dure 15. Chaque point de Maîtrise augmente le montant absorbé de ${150/100}.2' (length=128)
1 =>
array (size=1)
0 => string '150/12.5}% du montant de points de vie rendus et dure 15. Chaque point de Maîtrise augmente le montant absorbé de ${150/100' (length=123)
2 =>
array (size=1) 0 => string '2' (length=1)


Ce qui n'est pas du tout ce qu'on attend sad
Du coup ça me laisse totalement perplexe, car je peux avoir des ${..} avec quantificateurs de précision avant ceux sans, et vice-versa...
Je ne m'y connais pas particulièrement en PHP mais en expression régulière, je me débrouille. Si j'ai bien compris tu veux capturer le contenu entre crochets et le nombre qui arrive juste après s'il existe.
Dans ce cas là ton expression devrait être \$\{(.+?)\}(?:\.([0-9]+))?

Il faut enlever le point d’interrogation final si tu ne veux capturer que lorsque les crochets sont suivis d'un point. N'étant pas un connaisseur de PHP, je te laisse faire l'échappement toi même.
avatar
À cause de gros problèmes de connexions (FrozenWay + hotspot sfr qui perd 90% des paquets vtff), je n'ai pas pu éditer mon message, faute d'avoir essayé trois fois de suite...

J'ai fini par aboutir à celle que tu me préconises. En fait, pour une raison qui m'échappe, le flag ungreedy n'est pas nécéssaire dans ce cas... Merci pour les réponses en tout cas wink
C'est le point d'interrogation en fin de l'expression que tu appelles ungreedy? Si c'est le cas, c'est normal qu'il ne fonctionne pas comme tu le souhaite car ce n'est absolument pas un "ungreedy".

Dans les expression régulière perl le point d'interrogation peut avoir pas mal de significations différentes selon l'endroit où il est placé:
-après un caractère, un groupe ou une classe, il indique que cet elément est optionnel (présent 0 ou une fois)
-après un quantifieur ( *, +, ?, {n,m}) il indique que ce quantifieur est ungreedy : il capturera seulement la quantité minimale permettant d'obtenir une correspondance valide
-en début de groupe, il indique un comportement particulier de ce groupe (non capturant, lookaroud, ...)

Dans ton exemple, le ? final n'est pas un ungreedy car il est placé en fin de groupe. Il indique que le groupe qui le précède est optionnel.
avatar
Je pense que Warpten faisait référence au U qu'il plaçait après l'expression régulière. Et en effet, il n'est pas nécessaire puisqu'un ? a été placé après le +, seul endroit où il faut récupérer la chaîne la plus courte possible.
avatar
Je parlais bien de l'attribut U, merci pour les réponses wink
Ok, vu que je fais plutôt du java, je ne connaissait pas cette option spécifique à PHP
avatar