使用大型文档时,正常表达式非常慢

时间:2008-10-02 16:01:40

标签: c# regex performance

我需要将内联css样式属性转换为HTML标记equivelants。我已经工作的解决方案,但使用Microsoft .Net Regex命名空间和长文档(约40页的html)非常缓慢地运行。我尝试了几种变化,但没有有用的结果。我已经完成了执行表达式的一些包装,但最后它只是被调用的内置正则表达式替换方法。

我确定我正在滥用正则表达式的贪婪,但我不确定如何使用单个正则表达式实现我想要的东西。

我希望能够运行以下单元测试:

[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);
}

我用来实现这种逻辑的常规表达工作但非常慢。 c#代码中的正则表达式如下所示:

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>");
}

4 个答案:

答案 0 :(得分:7)

我认为问题在于,如果找到没有定义样式属性的span | font标签,由于“。*?”,它将继续查找它直到文档结尾。我没有测试过它,但把它改成“[^&gt;] *?”可能会提高绩效。

编辑:确保对所有“。*?”应用该更改。你有;甚至是捕获标签之间内容的那个(使用“[^&lt;] *?”),因为如果文件格式不正确,它将捕获到下一个结束标签。

答案 1 :(得分:0)

.NET正则表达式不支持递归构造。 PCRE可以,但这并不重要。

海外商品会有

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

它将被转换为

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

我的建议是使用正确的标记解析器,也可以在样式标记的值上使用regexp。

编辑:抓一点。 .NET似乎有一个平衡的递归模式构造。但没有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".

有关详细信息,请参阅http://weblogs.asp.net/whaggard/archive/2005/02/20/377025.aspx

答案 2 :(得分:0)

狂野猜测:我认为成本来自替代和相应的匹配。 您可能想尝试替换:

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

有两个单独的表达式:

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

当然,将文件解析加倍,但正则表达式更简单,使用更少的引用,实际上可能更快。它不是很好(重复代码)但只要它有效......

有趣的是,我做了类似的事情(我没有手头的代码)来清理工具生成的HTML,简化它以便JavaHelp可以理解它...这是针对HTML的正则表达式的一种情况,因为它不是一个人犯错误或改变创造HTML的小东西,而是一个定义明确的模式的过程。

答案 3 :(得分:0)

在测试期间,我发现了奇怪的行为。在单独的线程中运行regexp时,运行速度要快得多。 我有sql脚本,我正在使用regexp分为Go to Go中的部分。 在不使用单独线程的情况下处理此脚本时,它持续约2分钟。但是当使用多线程时,它只持续几个小时。