2009-05-12 3 views
2

J'utilise l'expression régulière à une balise de commentaire de supprimer dans le fichier html (Pattern est: « <!--(.|\s)*?--!?> »)Comment empêcher l'expression régulière de blocage (ou le temps prévu pour elle) en .Net

Mais certains sites ne sont pas en utilisant une balise HTML standard, exemple:

<script language="javascript"> 
    <!-- 
    js code ... 
    </script> 

Dans ce cas, mon expression régulière se bloque, et essayer la capture accessoire aussi ne pas attraper erreur. Comment pourrais-je remédier à ce problème?

Répondre

2

Vous pouvez réécrire l'expression régulière de sorte qu'il ne le plus rapidement possible lorsque aucune correspondance est possible, comme ceci:

<!--(?>(?:[^-]+|-(?!->))*)--> 

Si le commentaire non fermé dans votre exemple est suivi d'un commentaire complet plus loin, ce regex correspondra à partir du premier <!-- au premier -->, comme ceci:

<!-- blah <!-- blah --> 

Voilà comment votre navigateur est censé traiter les commentaires SGML. En fait, s'il n'y a pas de --> correspondant, tout ce qui suit le <!-- est commenté. Donc, la regex devrait vraiment être:

<!--(?>(?:[^-]+|-(?!->))*)(?:-->|\z) 

Mais je soupçonne que ce n'est pas vraiment ce que vous voulez. Pour une meilleure réponse, nous devrons savoir ce que vous voulez faire du HTML malformé, comme l'extrait que vous avez posté.

10

Le problème avec les performances de votre regex est trivial. Ne pas faire:

(.|\s)* 

Que le quantificateur est paresseux ou cupide tout à fait d'ailleurs le point. Le problème est que . et \ s ne sont pas mutuellement exclusifs. Les espaces peuvent être assortis par les deux. et \ s. Ainsi, si votre regex rencontre un espace, il va d'abord faire correspondre l'espace avec., Et si le reste de l'expression régulière échoue, il le fera correspondre à nouveau avec \ s. Si vous avez deux espaces, il va d'abord correspondre à la fois avec., Puis le premier avec. et la seconde avec \ s, puis la première avec \ s et la seconde avec., et ensuite les deux avec \ s. Comme vous pouvez le voir, votre regex a une complexité de O (2^N) quand il rencontre une série d'espaces suivie par quelque chose que le reste de l'expression rationnelle ne peut pas égaler. Si vous avez 10 espaces, il y a 1024 permutations. Si vous avez 32 espaces, il y a 4 milliards de permutations.

La raison pour laquelle vous ne voyez que le problème lorsque votre regex échoue est que lorsque l'expression régulière réussit, le. correspond simplement à tous les espaces et n'obtient jamais l'action.

Je sais ce que vous essayez de faire: vous voulez faire correspondre une série de caractères "quelconques", y compris des sauts de ligne, qui ne correspondent normalement pas au point. La bonne solution est de mettre RegexOptions.SingleLine et utiliser cette regex place:

.* 

Si vous ne pouvez pas définir RegexOptions.SingleLine, utilisez ce modificateur de mode pour faire la même chose:

(?s).* 

Si vous ne peut pas utiliser ce modificateur de mode, par exemple parce que JavaScript ne supporte pas, utilisez une classe de caractères avec deux complémentaires sténographies:

[\S\s]* 

Une fois que vous obtenez cette horrible (.| \ s) l'alternance de votre regex fonctionnera parfaitement. Il n'y a pas besoin d'utiliser les regex complexes que les autres suggèrent. Un seul quantificateur paresseux se développe toujours linéairement. Une alternance qui n'est pas mutuellement exclusive tue toujours votre regex. Je l'appelle en effet catastrophic backtracking.

Et si vous voulez une expression régulière qui permet une étiquette de mettre fin à un commentaire, essayez ceci:

(?s)<!--.*?(-->|</script>) 
+0

Ce '(? S) |) 'peut provoquer un dépassement de délai avec de grands textes d'entrée qui n'ont pas' -> 'ou' '. L'appariement paresseux est une solution médiocre pour ce cas. Découvrez la technique de dérouler la boucle. Cependant, dans des contextes spécifiques, toute regex échouera. –

+0

Lorsque cette expression régulière rencontrera '' ou ''. Il n'y a aucun moyen de le faire plus efficacement avec une seule regex si vraiment tout devrait être autorisé entre '' ou ''. Dérouler la boucle s'applique à certaines regexes où l'alternance est répétée, ce qui n'est pas le cas ici. –

+0

On ne peut pas être trop sûr quand il s'agit de regex: voir [votre regex] (https://regex101.com/r/wK8dW5/1) vs [mon regex ') [^-] * | <(?!\/script>) [^ <]*)*(--> | <\/script>) '] (https://regex101.com/r/wK8dW5/2). Au moins 20 fois plus efficace. –

Questions connexes