Précédent   Forum des professionnels en informatique > PHP > Langage > Regex
Regex Forum d'entraide sur les expressions rationnelles PHP. Avant de poster -> FAQ regex, Cours de regex et Sources de regex
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 06/05/2011, 10h03   #1
Modérateur
 
Avatar de Bisûnûrs
 
Josselin
Développeur Web
Inscription : janvier 2004
Messages : 9 050
Détails du profil
Informations personnelles :
Nom : Josselin
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : janvier 2004
Messages : 9 050
Points : 12 181
Points : 12 181
Par défaut Optimisation d'un pattern

Salut,

Je suis en train de créer un mini moteur de template qui se veut dynamique, et je me posais quelques questions sur les performances de celui-ci. Je cherche donc à optimiser au maximum l'expression régulière et je viens de tomber sur quelques résultats assez surprenants ..

Par exemple :

Code :
1
2
3
4
5
6
7
$html   = '<p>{pseudo} -
{age} ans</p>';
$pseudo = 'Bisunurs';
$age    = '28';
 
preg_replace( '¤{([^{]*)}¤e', '$\\1', $html );
preg_replace( '¤{(.*)}¤Ue', '$\\1', $html );
Dans ce cas, j'ai toujours appris que le (.*) couplé du Ungreedy était lourd et gourmand en ressource. Ce qui est le cas, vu que la première ligne est plus rapide à s'exécuter.
Seulement d'après mes tests, elle ne l'est que de 0.00134 % ! Il me semblait pourtant que c'était vraiment beaucoup plus lourd ..

Autre exemple, avec un délimiteur plus évolué :

Code :
1
2
3
4
5
6
7
$html   = '<p>{:pseudo:} -
{:age:} ans</p>';
$pseudo = 'Bisunurs';
$age    = '28';
 
preg_replace( '¤{:(.*)(?!:{):}¤e', '$\\1', $html );
preg_replace( '¤{:(.*):}¤Ue', '$\\1', $html );
Dans ce cas en revanche C'est le Ungreedy qui remporte la partie et est 1.412 % plus rapide ..

Quelqu'un saurait-il pourquoi ?
Y aurait-il un meilleur moyen d'optimiser ce genre de script ?

Merci !
Bisûnûrs est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/05/2011, 11h08   #2
Membre chevronné
 
Homme
Développeur Web
Inscription : mars 2011
Messages : 399
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France, Paris (Île de France)

Informations professionnelles :
Activité : Développeur Web
Secteur : Finance

Informations forums :
Inscription : mars 2011
Messages : 399
Points : 662
Points : 662
Je n'ai pas les moyens de voir le temps que prennent ces 3 patterns suivant mais personnellement j'aurais tenté :

Code :
1
2
preg_replace( '/{:([a-zA-Z]+):}/e', "$\\1", $html ); // si bien sûr il n'y a que des lettres dans {:abcdef:} plutôt que de vérifier s'il n'y a pas d'autre accolades ouvrantes (ce qui est plus lourd, je pense).
preg_replace( '/{:(\w+):}/e', "$\\1", $html ); // si les chiffres sont aussi admis
Code :
preg_replace( '/{:(.*?):}/e', "$\\1", $html ); // La même mais qui est plus général et peut causer des erreurs...
Pouvez-vous voir le temps que prennent ceux-ci ?
__________________
Membre de StackOverflow, je suis un fervant utilisateur de PHP et de jQuery.
Après des études de graphisme, j'ai décidé de mélanger développement web et web design. J'ai ainsi donc créé mon site web mais aussi plusieurs projets personnels.
Dans les plus aboutis, vous pourrez trouver dans mon labo et dans mon devblog, un raccourcisseur d'url, un bookmarklet pour envoyer l'url de la page actuelle vers votre email pour lire plus tard ou sauvegarder, mon générateur de template HTML5, etc...
Shikiryu est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 06/05/2011, 11h40   #3
Modérateur
 
Avatar de Bisûnûrs
 
Josselin
Développeur Web
Inscription : janvier 2004
Messages : 9 050
Détails du profil
Informations personnelles :
Nom : Josselin
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : janvier 2004
Messages : 9 050
Points : 12 181
Points : 12 181
Citation:
Envoyé par Shikiryu Voir le message
Je n'ai pas les moyens de voir le temps que prennent ces 3 patterns suivant mais personnellement j'aurais tenté :

Code :
1
2
preg_replace( '/{:([a-zA-Z]+):}/e', "$\\1", $html ); // si bien sûr il n'y a que des lettres dans {:abcdef:} plutôt que de vérifier s'il n'y a pas d'autre accolades ouvrantes (ce qui est plus lourd, je pense).
preg_replace( '/{:(\w+):}/e', "$\\1", $html ); // si les chiffres sont aussi admis
Code :
preg_replace( '/{:(.*?):}/e', "$\\1", $html ); // La même mais qui est plus général et peut causer des erreurs...
Pouvez-vous voir le temps que prennent ceux-ci ?
Le premier est seulement 2 % plus rapide que le Ungreedy.
Le deuxième est environ 3.5 % plus rapide que le Ungreedy.
Le dernier est juste 1 % plus rapide que le Ungreedy.

Donc pas de différence significative ..

(Pour les temps affichés, j'ai remplacé les guillemets par des apostrophes dans la chaine de remplacement, ce qui fait gagner 0.5 % dans chacun des cas)
Bisûnûrs est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/05/2011, 11h47   #4
Modérateur
 
Inscription : septembre 2010
Messages : 7 103
Détails du profil
Informations forums :
Inscription : septembre 2010
Messages : 7 103
Points : 8 466
Points : 8 466
normalement la syntaxe correct serait :
(?<={)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?=})

mais c'est pas forcement rapide
__________________
http://blog.stealth35.com/
stealth35 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/05/2011, 11h57   #5
Modérateur
 
Avatar de Bisûnûrs
 
Josselin
Développeur Web
Inscription : janvier 2004
Messages : 9 050
Détails du profil
Informations personnelles :
Nom : Josselin
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : janvier 2004
Messages : 9 050
Points : 12 181
Points : 12 181
Citation:
Envoyé par stealth35 Voir le message
mais c'est pas forcement rapide
Non en effet.
Bisûnûrs est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/05/2011, 12h15   #6
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 984
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

Informations professionnelles :
Activité : Développeur Web
Secteur : High Tech - Opérateur de télécommunications

Informations forums :
Inscription : février 2010
Messages : 2 984
Points : 5 016
Points : 5 016
Après avoir moi aussi tenté de créer mon moteur de template (j'ai réussi un truc pas mal d'ailleurs mais ce n'est pas la question) avec des méta-balises et un jeu d'instructions simple pour les boucles et les filtres, je me suis rendu compte qu'on ne pouvait pas aller plus vite que la bonne vieille méthode:
Code :
1
2
3
4
5
6
7
 
<?php foreach ($users as $user): ?>
<div id="<?=$user->id?>">
  <span>Name: <?=$user->name?></span>
  <span>Surname: <?=$user->surname?></span>
</div>
<?php endforeach ?>
Je vous mets au défi de trouver un moteur de templates plus puissant et surtout plus efficace que PHP lui-même.
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 11
Vieux 06/05/2011, 12h22   #7
Modérateur
 
Avatar de Bisûnûrs
 
Josselin
Développeur Web
Inscription : janvier 2004
Messages : 9 050
Détails du profil
Informations personnelles :
Nom : Josselin
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : janvier 2004
Messages : 9 050
Points : 12 181
Points : 12 181
@Benjamin Delespierre : Je suis d'accord, mais dans mon cas c'était juste pour éviter aux intégrateurs de toucher au PHP, de faire des boucles for() au lieu de foreach() pour parcourir un tableau par exemple.

Pour moi tout seul, je mélange le HTML et le PHP sans problème.
Bisûnûrs est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 12/05/2011, 20h20   #8
Membre actif
 
Avatar de Causa Sui
 
Inscription : mai 2003
Messages : 133
Détails du profil
Informations forums :
Inscription : mai 2003
Messages : 133
Points : 172
Points : 172
Citation:
Envoyé par Bisûnûrs Voir le message
Dans ce cas en revanche C'est le Ungreedy qui remporte la partie et est 1.412 % plus rapide ..

Quelqu'un saurait-il pourquoi ?
Le principe des quantificateurs non-gourmands (ungreedy), c'est qu'ils essayent de capturer le moins de lettre possibles pour effectuer une capture.
Mettons que tu as une chaîne:
Code :
{aaaaaaaa}aaaaaaaaaaaaaaaa
où tu fais une capture avec (en mode gourmand)
Il va d'abord capturer {
Code :
{aaaaaaaa}aaaaaaaaaaaaaaaa
Puis le plus de lettres quelconques possibles (.+)
Code :
{aaaaaaaa}aaaaaaaaaaaaaaaa
Et essayer de capturer }, ce qui va échouer (puisqu'il n'y a plus de lettre). Il va ensuite essayer de faire un retour (backtrace), une lettre à la fois, et tenter de capturer à nouveau }.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
{aaaaaaaa}aaaaaaaaaaaaaaaa
Et il va enfin pouvoir capturer }
Code :
{aaaaaaaa}aaaaaaaaaaaaaaaa
Si tu utilise une expression non gourmade:
Code :
1
2
3
/{.+?}/
#ou bien
/{.+}/U
… il va faire le chemin inverse
Code :
1
2
3
4
5
6
7
8
9
10
11
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    {aaaaaaaa}aaaaaaaaaaaaaaaa
On voit bien ici que la méthode gourmande prend beaucoup plus d'étapes que la non gourmande…

Et pour ce qui est du modificateur U en fin de regexp, je le déconseillerais: il est plus intéressant de changer la gourmandise de chaque quantificateur individuellement que de modifier le comportement général du moteur. Qui plus est, cette syntaxe (U) est propre à PCRE, là où les quantificateurs +?, *?, {}? fonctionnent quasi partout (PCRE, Perl, Oniguruma, etc.).

Et pour ce qui est de la regex qui nous occupe, j'utiliserais:
Code :
1
2
preg_replace( '/{:(\w+):}/e', "$\\1", $html );
preg_replace( '/{:([^:]+):}/e', "$\\1", $html );
Visiblement, c'est rapide, et ça me semble le plus cohérent avec le but à atteindre. Vu qu'elle s'arrête au ":" de fermeture, le quantificateur à tout intérêt à être gourmand…
Causa Sui est déconnecté   Envoyer un message privé Réponse avec citation 30
Vieux 13/05/2011, 09h13   #9
Modérateur
 
Avatar de Bisûnûrs
 
Josselin
Développeur Web
Inscription : janvier 2004
Messages : 9 050
Détails du profil
Informations personnelles :
Nom : Josselin
Âge : 29
Localisation : France, Rhône (Rhône Alpes)

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : janvier 2004
Messages : 9 050
Points : 12 181
Points : 12 181
@Causa Sui : Merci pour ton explication détaillée !

Concernant mon problème original, je m'étais un peu fourvoyé lors de la conception du pattern. En effet, je l'avais fait totalement généraliste, alors qu'il s'agit finalement de la syntaxe des variables PHP.
J'ai pris simplement la syntaxe proposée par Shikiryu : preg_replace( '/{:([a-zA-Z]+):}/e', "$\\1", $html ); à laquelle j'ai rajouté l'underscore et les chiffres.
Bisûnûrs est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 09h03.


 
 
 
 
Partenaires

Hébergement Web