代码之家  ›  专栏  ›  技术社区  ›  Ben McNiel

使用静态正则表达式。IsMatch与创建Regex实例

  •  49
  • Ben McNiel  · 技术社区  · 17 年前

    在C#中,你应该有这样的代码:

    public static string importantRegex = "magic!";
    
    public void F1(){
      //code
      if(Regex.IsMatch(importantRegex)){
        //codez in here.
      }
      //more code
    }
    public void main(){
      F1();
    /*
      some stuff happens......
    */
      F1();
    }
    

    还是应该持久化一个包含重要模式的Regex实例?使用Regex的成本是多少。IsMatch?我想每个Regex维护中都创建了一个NFA。据我所知,创建NFA并非易事。

    7 回复  |  直到 17 年前
        1
  •  57
  •   Community Mohan Dere    9 年前

    与我典型的自负不同,我在这个答案上有点颠倒了自己。

    我的原始答案保存在下面,是基于对版本的检查 1.1 的。NET框架。这很可耻,因为。NET 2.0在我回答时已经发布了三年多,它包含了对 Regex 类显著影响静态方法和实例方法之间的差异。

    在。NET 2.0(和4.0),静态 IsMatch 函数定义如下:

    public static bool IsMatch(string input, string pattern){
        return new Regex(pattern, RegexOptions.None, true).IsMatch(input);
    }
    

    这里的显著区别是 true 作为第三个论点。这对应于一个名为“useCache”的参数。如果这是真的,那么在第二次和后续使用时,将从缓存中检索解析后的树。

    这种缓存消耗了静态方法和实例方法之间的大部分性能差异。在我的测试中,静态 IsMatch 方法仍然比实例方法慢约20%,但当在10000个输入字符串上运行100次时(总共100万次操作),只增加了约半秒。

    在某些情况下,这20%的放缓仍然可能很严重。如果你发现自己要重新排列数亿个字符串,你可能会想尽一切办法提高效率。但我敢打赌,99%的情况下,你使用一个特定的正则表达式的次数不会超过几次,而静态方法所损失的额外毫秒甚至不会很明显。

    道具 devgeezer ,他几乎一年前就指出了这一点,尽管似乎没有人注意到。

    我的旧答案如下:


    静态 IsMatch 函数定义如下:

    public static bool IsMatch(string input, string pattern){
        return new Regex(pattern).IsMatch(input);
    }
    

    是的,初始化 正则 这个对象不是微不足道的。你应该使用静态 IsMatch (或任何其他静态 正则 函数)作为仅用于只使用一次的模式的快捷方式。如果你想重用这个模式,那么重用一个 正则 对象,也是。

    至于你是否应该具体说明 RegexOptions.Compiled 正如Jon Skeet所说,这是另一个故事。答案是:这取决于。对于简单的模式或只使用过几次的模式,使用非编译实例可能会更快。在决定之前,你绝对应该先分析一下。编译正则表达式对象的成本确实很高,可能不值得。


    以以下为例:

    const int count = 10000;
    
    string pattern = "^[a-z]+[0-9]+$";
    string input   = "abc123";
    
    Stopwatch sw = Stopwatch.StartNew();
    for(int i = 0; i < count; i++)
        Regex.IsMatch(input, pattern);
    Console.WriteLine("static took {0} seconds.", sw.Elapsed.TotalSeconds);
    
    sw.Reset();
    sw.Start();
    Regex rx = new Regex(pattern);
    for(int i = 0; i < count; i++)
        rx.IsMatch(input);
    Console.WriteLine("instance took {0} seconds.", sw.Elapsed.TotalSeconds);
    
    sw.Reset();
    sw.Start();
    rx = new Regex(pattern, RegexOptions.Compiled);
    for(int i = 0; i < count; i++)
        rx.IsMatch(input);
    Console.WriteLine("compiled took {0} seconds.", sw.Elapsed.TotalSeconds);
    

    count = 10000 如所列,第二个输出最快。增加 count 100000 ,编译版本获胜。

        2
  •  34
  •   ewwink    8 年前

    如果你打算多次重用正则表达式,我会用 RegexOptions.Compiled 并缓存它。让框架在每次需要时解析正则表达式模式是没有意义的。

        3
  •  13
  •   devgeezer    14 年前

    对于的版本,此答案不再正确。NET,我的机器上有。 4.0.30319&2.0.50727都有以下IsMatch功能:

    public static bool IsMatch(string input, string pattern)
    {
      return new Regex(pattern, RegexOptions.None, true).IsMatch(input);
    }
    

    'true'值用于名为“useCache”的构造函数参数。所有Regex构造函数最终都链接到这个构造函数中,静态函数直接称之为“true”。

    您在BCL博客文章中阅读了更多关于优化Regex性能的内容,重点介绍了静态方法的缓存使用 here 。这篇博客文章还引用了性能指标。阅读一系列关于优化Regex性能的博客文章是一个很好的起点。

        4
  •  8
  •   Andrew Hare    17 年前

    我同意Jon的观点,只是为了澄清一下,它看起来像这样:

    static Regex regex = new Regex("regex", RegexOptions.Compiled);
    

    它也值得一看 RegexOptions 枚举其他有时可能有用的标志。

        5
  •  6
  •   Ben Lings    17 年前

    有很多因素会影响使用正则表达式的性能。最终,找出在你的情况下表现最好的唯一方法是使用尽可能现实的情况进行衡量。

    页面在 compilation and reuse MSDN上的正则表达式对象涵盖了这一点。总之,它说

    1. 编译后的正则表达式需要时间来编译,一旦编译,它们的内存只会在 AppDomain 卸载。是否应该使用编译将取决于您使用的模式数量以及使用频率。

    2. 静态的 Regex 方法缓存最后15个(默认情况下)模式的解析正则表达式表示。因此,如果您在应用程序中没有使用许多不同的模式,或者您的使用方式已经足够集群化,那么两者之间就不会有太大区别 缓存实例或框架缓存它。

        6
  •  3
  •   Recep    17 年前

    我建议你阅读 Jeff's post 编译Regex。

    至于这个问题,如果你问这个问题,这意味着你只会使用一次。因此,Reflector对Regex的分解并不重要。IsMatch是:

    public static bool IsMatch(string input, string pattern, RegexOptions options)
    {
        return new Regex(pattern, options, true).IsMatch(input);
    }
    
        7
  •  3
  •   benPearce    17 年前

    对于我正在开发的WinForm应用程序,我们可以在有效字符上定义一个正则表达式,该正则表达式将在每次按键时运行,并对任何文本框(数据输入应用程序)的文本进行验证,因此我使用了缓存或编译的正则表达式,例如

      private static Dictionary<string, Regex> regexCache = new Dictionary<string, Regex>(20);
    

    正则表达式是关键。

    然后,我有一个静态函数,可以在验证数据时调用:

    public static bool RegExValidate(string text, string regex)
    {
      if (!regexCache.ContainsKey(regex))
      {
        Regex compiledRegex = new Regex(regex,RegexOptions.Compiled);
        regexCache.Add(regex, compiledRegex);
      }
      return regexCache[regex].IsMatch(text);
    }