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 PHP Discussion :

Optimisation d'un pattern [RegEx]


Sujet :

Langage PHP

  1. #1
    Modérateur
    Avatar de Bisûnûrs
    Profil pro
    Développeur Web
    Inscrit en
    Janvier 2004
    Messages
    9 868
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Janvier 2004
    Messages : 9 868
    Points : 16 258
    Points
    16 258
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 !

  2. #2
    Membre éclairé

    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2011
    Messages
    411
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 411
    Points : 735
    Points
    735
    Par défaut
    Je n'ai pas les moyens de voir le temps que prennent ces 3 patterns suivant mais personnellement j'aurais tenté :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 ?
    Je suis fervent 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 de développeur web dans le Val d'Oise mais aussi plusieurs projets personnels.
    Dans les plus aboutis, vous pourrez trouver dans mon labo et dans mon devblog, une extension de navigateur 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…

  3. #3
    Modérateur
    Avatar de Bisûnûrs
    Profil pro
    Développeur Web
    Inscrit en
    Janvier 2004
    Messages
    9 868
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Janvier 2004
    Messages : 9 868
    Points : 16 258
    Points
    16 258
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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)

  4. #4
    Expert éminent sénior

    Profil pro
    Inscrit en
    Septembre 2010
    Messages
    7 920
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2010
    Messages : 7 920
    Points : 10 726
    Points
    10 726
    Par défaut
    normalement la syntaxe correct serait :
    (?<={)[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?=})

    mais c'est pas forcement rapide

  5. #5
    Modérateur
    Avatar de Bisûnûrs
    Profil pro
    Développeur Web
    Inscrit en
    Janvier 2004
    Messages
    9 868
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Janvier 2004
    Messages : 9 868
    Points : 16 258
    Points
    16 258
    Par défaut
    Citation Envoyé par stealth35 Voir le message
    mais c'est pas forcement rapide
    Non en effet.

  6. #6
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

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

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

  7. #7
    Modérateur
    Avatar de Bisûnûrs
    Profil pro
    Développeur Web
    Inscrit en
    Janvier 2004
    Messages
    9 868
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Janvier 2004
    Messages : 9 868
    Points : 16 258
    Points
    16 258
    Par défaut
    @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.

  8. #8
    Membre actif Avatar de Causa Sui
    Inscrit en
    Mai 2003
    Messages
    133
    Détails du profil
    Informations forums :
    Inscription : Mai 2003
    Messages : 133
    Points : 209
    Points
    209
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    où tu fais une capture avec (en mode gourmand)
    Il va d'abord capturer {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    Puis le plus de lettres quelconques possibles (.+)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    {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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    {aaaaaaaa}aaaaaaaaaaaaaaaa
    Si tu utilise une expression non gourmade:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /{.+?}/
    #ou bien
    /{.+}/U
    … il va faire le chemin inverse
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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…

  9. #9
    Modérateur
    Avatar de Bisûnûrs
    Profil pro
    Développeur Web
    Inscrit en
    Janvier 2004
    Messages
    9 868
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Janvier 2004
    Messages : 9 868
    Points : 16 258
    Points
    16 258
    Par défaut
    @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.

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

Discussions similaires

  1. Optimisation de votre SGBDR et de vos requêtes...
    Par SQLpro dans le forum Langage SQL
    Réponses: 35
    Dernier message: 11/01/2013, 11h49
  2. [langage] Optimiser la lecture d'un fichier
    Par And_the_problem_is dans le forum Langage
    Réponses: 4
    Dernier message: 05/02/2003, 08h54
  3. [VB6] [BDD] Optimisation de l'accès aux données
    Par LadyArwen dans le forum VB 6 et antérieur
    Réponses: 8
    Dernier message: 30/01/2003, 13h27
  4. [langage]Problème de temps de lecture, optimisation
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 08/01/2003, 08h47
  5. [langage] Optimiser la lecture d'un fichier
    Par And_the_problem_is dans le forum Langage
    Réponses: 2
    Dernier message: 11/06/2002, 10h24

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