2009-09-15 5 views
4

Avis de non-responsabilité: Je ne suis pas un expert en regex. J'utilise Python re module pour effectuer une correspondance regex sur de nombreux fichiers htm. L'un des modèles est quelque chose comme ceci:Est-il possible de faire re trouver le plus petit match tout en utilisant des caractères avides

<bla><blabla>87765.*</blabla><bla> 

Le problème que je l'ai rencontré est que, au lieu de trouver tous les (disons) cinq occurrences du motif, il trouvera qu'un seul. Parce qu'il fusionne toutes les occurrences en une, en utilisant la partie <bla><blabla>87765 de la première occurrence et la partie </blabla><bla> de la dernière occurrence dans la page.

Existe-t-il un moyen de dire à re de trouver la plus petite correspondance?

+0

exclure '<' du modèle – SilentGhost

+6

Si seulement il y avait des centaines de bibliothèques pour analyser HTML, ce serait tellement plus facile ... oh, attendez. –

+0

^^ quelle façon ennuyeuse d'approcher la vie. Peut-être qu'il fera le meilleur pour le moment. –

Répondre

13

Vous pouvez utiliser un qualificatif réticent dans votre modèle (pour plus de détails, faire référence à la python documentation sur les *?, +? et ?? opérateurs):

<bla><blabla>87765.*?</blabla><bla> 

Ou, exclure < des caractères correspondants possibles:

<bla><blabla>87765[^<]*</blabla><bla> 

seulement s'il n'y a pas de balises enfants entre <blabla> et </blabla>.

+0

La suggestion '[^ <]' échouera s'il y a des balises enfants entre '' et ''. – tzot

0

Um ... il y a un moyen de dire à re de trouver la plus petite correspondance, et c'est précisément en utilisant non-gourmand quantificateurs.

<bla><blabla>87765.*?</blabla><bla> 

Je ne peux pas imaginer pourquoi vous voudriez le faire en utilisant des quantificateurs gourmands.

+0

Parce que je ne savais pas à leur sujet et n'ai pas compris leur utilisation :) –

1

Le module Python re prend en charge la correspondance non récurrente. Vous venez d'ajouter un ? à la fin du motif générique, tel que .*?. Vous pouvez en apprendre plus au this HOWTO.

+1

Correspondance non-gourmande n'est pas une solution à cette question. Essayez le modèle «premier quelque chose première seconde» et le modèle «premier (. *?) Deuxième».Même s'il n'est pas gourmand, il prendra toujours le premier match qu'il trouve, qui est le plus grand, le plus à gauche. La gourmandise affecte juste comment il traite le modèle à chaque caractère. –

1
I believe the regex 
<bla><blabla>87765.*?</blabla><bla> 
can produce catastrophic backtracking. 

Instead, use: 
<bla><blabla>87765[^<]*</blabla><bla> 

Using atomic grouping (I'm not sure Python supports this), 
the above regex becomes 
<bla><blabla>(?>(.*?<))/blabla><bla> 

Tout entre (?> ...) est traité comme un seul jeton par le moteur regex, une fois que le moteur regex quitte le groupe. Comme le groupe entier est un jeton, aucun retour arrière ne peut avoir lieu une fois que le moteur d'expressions régulières a trouvé une correspondance pour le groupe. Si un retour en arrière est nécessaire, le moteur doit revenir sur le jeton regex avant le groupe (le curseur dans notre exemple). S'il n'y a pas de jeton avant le groupe, l'expression régulière doit réessayer la regex entière à la position suivante dans la chaîne. Notez que j'avais besoin d'inclure le "<" dans le groupe pour assurer l'atomicité. Assez proche.

+0

Avec seulement un quantificateur et aucune alternance, je ne vois pas de potentiel de retour en arrière catastrophique. La version '. *?' Pourrait être moins efficace que '[^ <] *' mais vous ne remarquerez probablement jamais la différence. Et non, Python ne supporte pas les groupes atomiques. –

Questions connexes