【问题标题】:Optimize performance with multiple calls to Regex.IsMatch on large text通过对大文本多次调用 Regex.IsMatch 来优化性能
【发布时间】:2015-07-15 14:03:02
【问题描述】:

我有一个长文本(50-60 KB),我需要针对它运行几个正则表达式(总共大约 100 条规则)。但是,这太慢了,以至于它基本上不起作用。

我所做的只是围绕规则创建一个循环,其中每个规则执行一个Regex.IsMatch()

有没有办法优化这个?

更新

每个规则执行的示例代码:

public class SomeRegexInterceptor : ValidatorBase
    {
        private readonly Regex _rgx = new Regex("some regex", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline); 

        public override void Intercept(string html, ValidationResultCollection collection)
        {
            if (!_rgx.IsMatch(html)) return;

            /* do something irrelevant here */
        }
    }

【问题讨论】:

  • 确保使用RegexOptions.Compiled 标志在循环外初始化正则表达式。还要尽可能多地从循环中删除。如果您可以逐行工作,请尝试这样做,而不是搜索一个 50-60KB 的巨大字符串。
  • @AeroX - 我不是你可以查看示例代码以供参考
  • 你在哪里创建了这个类实例多少次?它不是静态的,正则表达式在实例创建时被初始化。那是低效的。
  • 正则表达式本身也很可能/需要优化。对每个正则表达式匹配进行计时,以查看是否存在需要非常长时间才能匹配(或无法匹配)的正则表达式。此类问题通常来自catastrophic backtracking

标签: c# regex


【解决方案1】:

使用正则表达式替换最重要的一点是您声明正则表达式的方式和位置。 切勿在循环内初始化 Regex 对象。

创建一个静态类并添加带有RegexOptions.Compiled 标志的public static readonly 正则表达式字段。

然后,在任何需要的地方使用它们,例如 MyRegexClass.LeadingWhitespace.Replace(str, string.Empty)

注意,如果需要使用Regex.Replace,则不需要检查之前是否与Regex.IsMatch匹配。

阅读并遵循Best Practices for Regular Expressions in the .NET Framework 中列出的建议,即:

此外,请考虑逐行处理文件,并尽可能避免使用正则表达式。

【讨论】:

  • 嘿 - 请检查提供的示例代码。我不认为我在做任何疯狂的事情。
  • 也许,用正则表达式解析 HTML 是个坏主意? ;-) 我确信问题出在一些导致大量回溯的正则表达式上。调试你的表达式并检查执行失败的地方。修复图案。重复。特别关注.*
  • 那个 .* 是罪魁祸首。谢谢
  • 我想补充一点,我怀疑在循环中构造正则表达式甚至不使用 RegexOptions.Compiled 因为 C# 使用 Regex.CacheSize 缓存正则表达式会产生重大问题,只要你有Regex数量比较少,应该是比较差不多的docs.microsoft.com/en-us/dotnet/standard/base-types/…
  • @derekantrican 实际上,随着最新的发展,.NET 正则表达式变得更加稳定,并且不太容易出现灾难性回溯等问题。这个 6 年前的答案反映了我们在我的以前的工作。
【解决方案2】:

你能把你的规则合并成一个规则吗?例如:如果你为“aaa”做一个正则表达式,然后为“bbb”做一个,组合成“aaa|bbb”会大大提高性能(而不是运行两个单独的正则表达式)。我以前以这种方式以编程方式组合了大量的正则表达式,它产生了巨大的性能差异。

【讨论】:

    【解决方案3】:

    组合表达式

    如果您有能力在运行规则之前完成工作,您可以将正则表达式与| 结合起来,一次性完成搜索。然后在您的规则中,您不会像以前那样匿名检查匹配,而是按组的名称。例如

    >((?<Ex1>expression1)|(?<Ex2>expression2)|(?<Ex3>expression3))
    

    因此,关心组Ex1 的规则会检查该组。关心Ex2 的规则检查Ex2 等等。

    此外,您还可以分析正则表达式集并以某种方式对其进行优化。除非您正在做一些简单的事情,例如消除重复项,否则这将是一项非常程序化的壮举。

    缓存、缓存大小

    另一个想法是在某处缓存并编译所有正则表达式,更改Regex.CacheSize 的大小以查看是否有帮助。 documentation 声明默认值为 15,但您已经结束了。

    更多信息

    关于一次实例化和编译表达式的 cmets 是有效的。还有其他建议from MSDN

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-26
      • 2012-09-26
      相关资源
      最近更新 更多