2008-10-16 6 views
56

Existe-t-il un moyen en PHP pour compiler une expression régulière, de sorte qu'il puisse ensuite être comparé à plusieurs chaînes sans répéter le processus de compilation? D'autres langues principales peuvent le faire - Java, C#, Python, Javascript, etc.Compile regex en PHP

Répondre

4

Je ne suis pas certain que vous le pouvez. Si vous consultez Mastering Regular Expressions, certaines techniques d'optimisation spécifiques à PHP sont abordées au Chapitre 10: PHP. Plus précisément, l'utilisation du modificateur de pattern S pour amener le moteur regex à "étudier" l'expression régulière avant de l'appliquer. Selon votre modèle et votre texte, cela pourrait vous apporter des améliorations de vitesse.

Édition: vous pouvez jeter un coup d'œil au contenu du livre en utilisant books.google.com.

+0

Chaque développeur qui utilise regex devrait lire ce livre !! Toutes les techniques dont vous avez besoin pour être efficace sont dans ce livre. – Arno

17

Les expressions rationnelles peuvent utiliser le modificateur majuscule S (étude), qui est probablement ce que vous cherchez.

http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

S

Lorsqu'un modèle va être utilisé plusieurs fois, il vaut la peine de dépenser plus de temps analyser afin de accélérer le temps pour la correspondance. Si ce modificateur est défini, cette analyse supplémentaire est effectuée. À présent, l'étude d'un modèle est utile uniquement pour les modèles non ancrés qui ont pas un seul caractère de départ fixe .

+9

La réponse à la question de l'OP est qu'il n'est pas nécessaire de précompiler les expressions rationnelles en PHP car, comme l'a noté 1stvamp, les expressions rationnelles compilées sont mises en cache automatiquement. Le modificateur 'S' est un problème distinct. –

+0

Cette réponse a été ajoutée à la [FAQ sur les expressions régulières de dépassement de capacité de la pile] (http://stackoverflow.com/a/22944075/2736496), sous "Modificateurs". – aliteralmind

39

La bibliothèque d'expressions régulières compatibles Perl peut déjà être optimisé pour votre cas d'utilisation sans fournir une classe Regex comme d'autres langages:

Cette extension maintient un cache global par thread de compilation régulière expressions (jusqu'à 4096).

PCRE Introduction

Voici comment le modificateur d'étude qui décrit Imran peut stocker l'expression compilée entre les appels.

+0

puis-je augmenter la taille de cache par thread et quelle est la signification de 4096 –

+0

Je suppose que 4096 signifie 4 kiloBytes, non? – tonix

+0

Je pense que cela signifie 4096 regex compilés. – Tobia

7

Comme un autre intervenant l'a déjà dit, les expressions régulières PCRE sont déjà compilées sans que vous ayez besoin de les référencer spécifiquement en tant que telles, PCRE conserve un hachage interne indexé par la chaîne d'origine que vous avez fournie.

12

Thread est le thread dans lequel le script est en cours d'exécution. Après la première utilisation, regexp compilé est mis en cache et la prochaine fois qu'il est utilisé PHP ne le compile pas à nouveau.

Test simple:

<?php 

function microtime_float() { 
    list($usec, $sec) = explode(" ", microtime()); 
    return ((float)$usec + (float)$sec); 
} 

// test string 
$text='The big brown <b>fox</b> jumped over a lazy <b>cat</b>'; 
$testTimes=10; 


$avg=0; 
for ($x=0; $x<$testTimes; $x++) 
{ 
    $start=microtime_float(); 
    for ($i=0; $i<10000; $i++) { 
     preg_match_all('/<b>(.*)<\/b>0?/', $text, $m); 
    } 
    $end=microtime_float(); 
    $avg += (float)$end-$start; 
} 

echo 'Regexp with caching avg '.($avg/$testTimes); 

// regexp without caching 
$avg=0; 
for ($x=0; $x<$testTimes; $x++) 
{ 
    $start=microtime_float(); 
    for ($i=0; $i<10000; $i++) { 
     $pattern='/<b>(.*)<\/b>'.$i.'?/'; 
     preg_match_all($pattern, $text, $m); 
    } 
    $end=microtime_float(); 
    $avg += (float)$end-$start; 
} 

echo '<br/>Regexp without caching avg '.($avg/$testTimes); 

Regexp avec la mise en cache avg 0,1 Regexp sans cache avg 0,8

Mise en cache un regexp fait 8 fois plus vite!

+2

** Le test est NUL **! Parce que: vous concaténez 3 chaînes dans votre 2ème exemple (sans mise en cache) tandis que dans la 1ère, la variable "$ i" n'existe pas dans le modèle et c'est toujours 0 à cet endroit –

+2

Le test est ** raisonnablement valide ** néanmoins. En concaténant une chaîne "$ j- $ y" avec $ j = 37 et $ y = 5 dans le premier test, et une chaîne "$ i- $ x" dans la seconde (le - $ x est de vaincre toute mise en cache par testTimes), j'obtiens des temps de 0.0112 et 0.0431. Le même 0.0431 est obtenu en utilisant "$ i- $ y" dans le deuxième test, ce qui signifie qu'en effet le cache a une taille inférieure à 10000. Mon accélération réelle est donc ** 4 fois plus rapide ** (pas 8). – LSerni