2008-10-02 7 views
2

Je dois convertir les attributs de style css en ligne en leurs équivalents de balises HTML. La solution que j'ai fonctionne mais fonctionne TRÈS lentement en utilisant l'espace de noms Microsoft .Net Regex et de longs documents (~ 40 pages de html). J'ai essayé plusieurs variantes mais sans résultats utiles. J'ai fait un peu de retour autour de l'exécution des expressions mais à la fin c'est juste la méthode regex intégrée qui est appelée. Je suis sûr que j'abuse de la gourmandise de la regex mais je ne suis pas sûr d'un moyen de contourner cela pour atteindre ce que je veux en utilisant une seule expression régulière.Expression régulière très lente lors de l'utilisation de documents volumineux

Je veux être en mesure d'exécuter les tests unitaires suivants:

[Test] 
public void TestCleanReplacesFontWeightWithB() 
{ 
    string html = "<font style=\"font-weight:bold\">Bold Text</font>"; 
    html = Q4.PrWorkflow.Helper.CleanFormatting(html); 
    Assert.AreEqual("<b>Bold Text</b>", html); 
} 
[Test] 
public void TestCleanReplacesMultipleAttributesFontWeightWithB() 
{ 
    string html = "<font style=\"font-weight:bold; color: blue; \">Bold Text</font>"; 
    html = Q4.PrWorkflow.Helper.CleanFormatting(html); 
    Assert.AreEqual("<b>Bold Text</b>", html); 
} 
[Test] 
public void TestCleanReplaceAttributesBoldAndUnderlineWithHtml() 
{ 
    string html = "<span style=\"font-weight:bold; color: blue; text-decoration: underline; \">Bold Text</span>"; 
    html = Q4.PrWorkflow.Helper.CleanFormatting(html); 
    Assert.AreEqual("<u><b>Bold Text</b></u>", html); 
} 
[Test] 
public void TestCleanReplaceAttributesBoldUnderlineAndItalicWithHtml() 
{ 
    string html = "<span style=\"font-weight:bold; color: blue; font-style: italic; text-decoration: underline; \">Bold Text</span>"; 
    html = Q4.PrWorkflow.Helper.CleanFormatting(html); 
    Assert.AreEqual("<u><b><i>Bold Text</i></b></u>", html); 
} 
[Test] 
public void TestCleanReplacesFontWeightWithSpaceWithB() 
{ 
    string html = "<font size=\"10\" style=\"font-weight: bold\">Bold Text</font>"; 
    html = Q4.PrWorkflow.Helper.CleanFormatting(html); 
    Assert.AreEqual("<b>Bold Text</b>", html); 
} 

Le expresion régulière J'utilise pour réaliser cette logique fonctionne, mais est très lent. Le regex dans le code C# ressemble à ceci:

public static IReplacePattern IncludeInlineItalicToITag(ICleanUpHtmlFactory factory) 
{ 
    return factory.CreateReplacePattern("(<(span|font) .*?style=\".*?font-style:\\s*italic[^>]*>)(.*?)</\\2>", "$1<i>$3</i></$2>"); 
} 
public static IReplacePattern IncludeInlineBoldToBTag(ICleanUpHtmlFactory factory) 
{ 
    return factory.CreateReplacePattern("(<(span|font) .*?style=\".*?font-weight:\\s*bold[^>]*>)(.*?)</\\2>", "$1<b>$3</b></$2>"); 
} 
public static IReplacePattern IncludeInlineUnderlineToUTag(ICleanUpHtmlFactory factory) 
{ 
    return factory.CreateReplacePattern("(<(span|font) .*?style=\".*?text-decoration:\\s*underline[^>]*>)(.*?)</\\2>", "$1<u>$3</u></$2>"); 
} 
+0

Avant de fournir une réponse, posez la question: Quelle version du framework .NET utilisez-vous? Si vous n'utilisez pas actuellement .NET 3.5, cela vaut-il la peine d'effectuer une mise à niveau? –

Répondre

7

Je crois que le problème est que si elle trouve une durée | de balise de police, qui n'a pas d'attribut de style défini, il continuera à sa recherche jusqu'à la fin de la document à cause du ". *?". Je n'ai pas testé, mais je l'ai changé en "[^>] *?" pourrait améliorer les performances.

EDIT: Assurez-vous d'appliquer cette modification pour tous les ". *?" tu as; même celui qui capture le contenu entre les balises (utilisez "[^ <] *?"), car si le fichier n'est pas bien formé, il capture jusqu'à la balise de fermeture suivante.

+0

Convenu. Chaque fois que vous essayez d'améliorer une regex (que ce soit pour la performance, la clarté, ou à peu près n'importe quoi d'autre),. * Est la première chose que vous devriez regarder et essayer d'éliminer. –

+0

Je suis totalement d'accord. J'ai partiellement hérité de la mise à jour de ce code alors j'essayais de le faire en utilisant le même modèle d'utilisation d'une regex - je n'aurais probablement pas utilisé une regex directe sinon. –

0

Les expressions régulières .NET ne prennent pas en charge les constructions récursives. PCRE fait, mais cela n'a pas d'importance ici.

concider

<font style="font-weight: bold;"> text1 <font color="blue"> text2 </font> text3 </font> 

Il obtiendriez converti en

<b> text1 <font color="blue"> text2 </b> text3 </font> 

Ma suggestion serait d'utiliser un analyseur de balisage approprié, et peut-être utiliser regexp sur les valeurs du style balises.

Editer: Grattez cela. Il semble que .NET ait une construction pour des motifs récursifs et équilibrés. Mais pas aussi puissant que ceux de PCRE/Perl.

(?<N>content) would push N onto a stack if content matches 
(?<-N>content) would pop N from the stack, if content matches. 
(?(N)yes|no) would match "yes" if N is on the stack, otherwise "no". 

Voir http://weblogs.asp.net/whaggard/archive/2005/02/20/377025.aspx pour plus de détails.

+0

Il est parfaitement possible de gérer cela dans NET. Voir les groupes d'équilibrage dans les expressions régulières, il vous permet de faire correspondre les parenthèses d'équilibrage, par exemple. http://oreilly.com/catalog/regex2/chapter/index.html –

0

Wild suppose: Je crois que le coût vient de l'alternative et la correspondance correspondante. Vous pouvez essayer de remplacer:

"(<(span|font) .*?style=\".*?font-style:\\s*italic[^>]*>)(.*?)</\\2>", "$1<i>$3</i></$2>" 

avec deux expressions distinctes:

"(<span .*?style=\".*?font-style:\\s*italic[^>]*>)(.*?)</span>", "$1<i>$2</i></span>" 
"(<font .*?style=\".*?font-style:\\s*italic[^>]*>)(.*?)</font>", "$1<i>$2</i></font>" 

Accordé, ce double l'analyse syntaxique du fichier, mais l'expression rationnelle étant plus simple, avec moins trackbacks, il pourrait être plus rapide en pratique. C'est pas très sympa (répétition de code) mais tant que ça marche ...

Bizarrement, j'ai fait quelque chose de similaire (je n'ai pas le code à portée de main) pour nettoyer le HTML généré par un outil, en simplifiant pour que JavaHelp puisse le comprendre ...C'est un cas où les expressions rationnelles contre HTML sont correctes, parce que ce n'est pas un humain qui commet des erreurs ou qui change de petites choses qui crée le HTML, mais un processus avec des motifs bien définis.

0

Pendant le test, j'ai trouvé un comportement étrange. Lorsque vous exécutez regexp dans un thread séparé, il s'exécute beaucoup plus rapidement. J'ai un script sql que je divisais en sections de Go to Go en utilisant regexp. Lorsque vous travaillez sur ce script sans utiliser de thread séparé, il dure environ 2 minutes. Mais en utilisant le multithreading il ne dure que quelques secondes.