【问题标题】:Why does my regex works very slow when it contains '\r'为什么我的正则表达式在包含 '\r' 时工作得非常慢
【发布时间】:2014-05-20 13:44:41
【问题描述】:

我只是想用另一个字符串替换一些 html 中的 header 标签。 我的 html 看起来像这样:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"><head><title>aboutus</title> 

    <header id="headerfasdfasdfasdf">
       <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer pulvinar commodo lorem, sit amet malesuada.</p>
    </header>

<!-- #include virtual="/html/US/global_header.html" --><script type="text/javascript">

   var header = document.getElementsByTagName("header");

    var len = header.length

    if(len > 1)

    {

    header[0].style.display = "none";

    }
</script>

    <!--ls:begin[component-1400226725207]-->

    <!-- OTHER PART IS CUT FOR BREVITY -->

</html>

我尝试使用正则表达式 &lt;header(.|\n|\r)*&lt;\/header&gt; 对其进行解析,但在我从中删除 |\r 部分之前,它的运行速度非常慢。

我还注意到原始正则表达式适用于不包含 &lt;!--ls:begin[component-1400226725207]--&gt; 之类的 cmets 的 html。

请注意,我正在使用带有 C# 的 .NET 正则表达式引擎,我的替换代码如下所示:

var regex = @"<header(.|\n|\r)*<\/header>";
var result = Regex.Replace(input, regex, to, RegexOptions.IgnoreCase);

请帮助我了解为什么会出现此问题。

【问题讨论】:

  • 为什么?浏览器不关心 CRLF,你不应该使用 RegEx 来解析 html。为什么不直接从渲染器中获取呢?
  • @mplungjan,我知道我不应该这样做,但我对这部分没有任何选择,我只有结果 html 和一些用于插入的部分。我更感兴趣的是为什么这个正则表达式在这部分工作缓慢。
  • 那个正则表达式 not 看起来很安全(是否需要贪婪?),但关于速度,请记住 .RegexOptions.Singleline 将匹配任何字符,包括换行符。跨度>
  • @Robin 感谢您对单行的建议。为什么它看起来不安全,为什么 '\r' 会减慢它的速度?

标签: c# html regex


【解决方案1】:

如果您的输入得到很好的清理(即,如果您觉得自己 can use regex to parse HTML),这可能会显着提高您的速度:

var regex = @"<header.*?</header>";
var result = Regex.Replace(input, regex, to, RegexOptions.IgnoreCase|RegexOptions.Singleline);
  • 完全避免使用.|\n|\r,你想做什么都有一个标志。
  • 让你的量词变得懒惰*?,因为标题标签可能不会占用你 HTML 的三分之二

当从文件末尾回溯到&lt;/header&gt; 时,(.|\n|\r)* 的贪婪使得正则表达式引擎在尝试&lt;/header&gt; 之前检查交替的每个元素。您添加到交替中的任何元素都可能需要更多的工作。

【讨论】:

    【解决方案2】:

    就个人而言,我会使用更简单的表达方式并告诉它 . (dot) 也匹配换行符:-

    (?s)(?U)<header.*\/header>
    

    (?s) 表示用 . 匹配换行符以及其他字符。 (点)
    (?U) 表示匹配尽可能少的字符

    【讨论】:

    • 当我在 Regex.Replace 中尝试您的正则表达式时 - 它显示 System.ArgumentException : parsing "(?s)(?U)" - 无法识别的分组构造。
    • 这是 PHP 正则表达式语法,不是 C#/POSIX
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 2013-11-05
    • 2014-05-04
    • 2021-11-25
    • 1970-01-01
    • 2018-11-26
    相关资源
    最近更新 更多