2009-03-25 2 views
6

J'ai un tableau rempli de motifs dont j'ai besoin. Tout moyen de le faire, autre qu'une boucle for()? Je suis en train d'essayer de le faire de la manière la moins intensive du CPU, puisque j'en ferai des dizaines toutes les minutes.Comment exécutez-vous un preg_match où le motif est un tableau, en php?

Un exemple concret est, Im la construction d'un vérificateur d'état de lien, qui vérifie les liens vers divers sites vidéo en ligne, pour s'assurer que les vidéos sont encore en direct. Chaque domaine a plusieurs "mots-clés morts", si ceux-ci se trouvent dans le html d'une page, cela signifie que le fichier a été supprimé. Ceux-ci sont stockés dans le tableau. Je dois faire correspondre le contenu du tableau, avec la sortie html de la page.

Répondre

20

Tout d'abord, si vous ne faites que des dizaines littéralement chaque minute , alors je ne vous inquiétez pas terriblement de la performance dans ce cas. Ces résultats sont assez rapides, et je ne pense pas que vous allez avoir un problème de performance par itérer vos modèles tableau et appelant preg_match comme séparément ceci:

$matches = false; 
foreach ($pattern_array as $pattern) 
{ 
    if (preg_match($pattern, $page)) 
    { 
    $matches = true; 
    } 
} 

Vous pouvez en effet combiner tous les modèles en un seul en utilisant l'opérateur or comme certaines personnes le suggèrent, mais ne les appliquez pas simplement avec un |. Cela va mal casser si l'un de vos modèles contient l'opérateur ou.

je recommande au moins grouper vos modèles en utilisant comme entre parenthèses:

foreach ($patterns as $pattern) 
{ 
    $grouped_patterns[] = "(" . $pattern . ")"; 
} 
$master_pattern = implode($grouped_patterns, "|"); 

Mais ... Je ne suis pas vraiment sûr si cela finit par être plus rapide. Quelque chose doit faire une boucle à travers eux, que ce soit le preg_match ou PHP. Si je devais deviner, je devinerais que les matchs individuels seraient aussi rapides et faciles à lire et à maintenir. Enfin, si la performance est ce que vous cherchez ici, je pense que la chose la plus importante à faire est de sortir les correspondances non regex dans une simple vérification "chaîne contient". J'imagine que certaines de vos vérifications doivent être de simples vérifications de chaînes comme si vous cherchiez à voir si «Ce site est fermé» se trouve sur la page.

fait donc ceci:

foreach ($strings_to_match as $string_to_match) 
{ 
    if (strpos($page, $string_to_match) !== false)) 
    { 
    // etc. 
    break; 
    } 
} 
foreach ($pattern_array as $pattern) 
{ 
    if (preg_match($pattern, $page)) 
    { 
    // etc. 
    break; 
    } 
} 

et en évitant autant que possible preg_match() va probablement être votre meilleur gain. strpos() est un lot plus rapide que preg_match().

+4

Pour le bien du Googler, pensez à utiliser break (http://www.php.net/manual/fr/control-structures.break.php) pour sortir de la boucle foreach une fois que vous avez trouvé un match! –

+2

Je crois que cela devrait être: foreach ($ pattern_array as $ pattern), au moins dans ma version de PHP – hellomynameisjoel

+1

Très bien vous les gars ... édité pour répondre à vos commentaires. – danieltalsky

0

Si vous avez un tas de modèles, vous pouvez les concaténer en une seule expression régulière et faire correspondre cela. Pas besoin d'une boucle.

1

Si vous recherchez simplement la présence d'une chaîne dans une autre chaîne, utilisez strpos car elle est plus rapide. Dans le cas contraire, vous pouvez simplement parcourir le tableau de modèles en appelant chaque fois preg_match.

10
// assuming you have something like this 
$patterns = array('a','b','\w'); 

// converts the array into a regex friendly or list 
$patterns_flattened = implode('|', $patterns); 

if (preg_match('/'. $patterns_flattened .'/', $string, $matches)) 
{ 
} 

// PS: that's off the top of my head, I didn't check it in a code editor 
+1

Est-ce que cela fonctionnera sans parenthèses/parenthèses autour des "motifs"? – JedatKinports

0

Que diriez-vous de faire un str_replace() sur le HTML que vous obtenez en utilisant votre tableau, puis en vérifiant si le HTML original est égal à l'original?Ce serait très rapide:

$sites = array(
     'you_tube' => array('dead', 'moved'), 
     ... 
); 
foreach ($sites as $site => $deadArray) { 
    // get $html 
    if ($html == str_replace($deadArray, '', $html)) { 
     // video is live 
    } 
} 
+0

str_replace ne fonctionne pas si vous voulez une correspondance exacte –

2

Si vos modèles ne contiennent pas beaucoup les espaces blancs, une autre option serait de les éviter et les tableaux utiliser le modificateur /x. Maintenant, votre liste d'expressions régulières ressemblerait à ceci:

$regex = "/ 
pattern1| # search for occurences of 'pattern1' 
pa..ern2| # wildcard search for occurences of 'pa..ern2' 
pat[ ]tern| # search for 'pat tern', whitespace is escaped 
mypat  # Note that the last pattern does NOT have a pipe char 
/x"; 

Avec le modificateur /x, des espaces est complètement ignorée, sauf si dans une classe de caractère ou précédée d'une barre oblique inverse. Les commentaires comme ci-dessus sont également autorisés.

Ceci éviterait la boucle dans le tableau.

Questions connexes