[使用大型文档时运行速度很慢的正则表达式

问题描述 投票:2回答:4

我需要将内联css样式属性转换为其HTML标记等价物。我拥有的解决方案有效,但是使用Microsoft .Net Regex命名空间和较长的文档(约40页html),运行速度非常慢。我尝试了几种变体,但没有任何有用的结果。我对执行表达式做了一些包装,但最后只是调用了内置的regex Replace方法。

我确定我在滥用正则表达式的贪婪,但不确定使用单个正则表达式来实现我想要的方法。

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

[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>");
}
c# regex performance
4个回答
7
投票

我相信问题是,如果找到span | font标记,但未定义样式属性,由于.\*?,它将继续寻找直到文档结尾。我尚未对其进行测试,但是将其更改为[^>]\*?可能会提高性能。

确保您对所有.\*?应用该更改;即使是捕获标签之间内容的标签(在那里使用[^<]\*?),因为如果文件格式不正确,它将捕获多达下一个结束标签。


0
投票

。NET正则表达式不支持递归构造。 PCRE可以,但是在这里无关紧要。

Concider

<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


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的不是人为的错误或小小的事情,而是具有明确定义的模式的过程。


0
投票

在测试期间,我发现了奇怪的行为。当在单独的线程中运行regexp时,它的运行速度要快得多。我有使用regexp从Go转到Go拆分为sql脚本的部分。在不使用单独线程的情况下使用此脚本时,该脚本持续约2分钟。但是,当使用多线程时,它仅持续数秒。

© www.soinside.com 2019 - 2024. All rights reserved.