C# 使用静态Regex.IsMatch与创建Regex实例

C# 使用静态Regex.IsMatch与创建Regex实例,c#,regex,optimization,C#,Regex,Optimization,在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(); } 或者应该持久化

在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.IsMatch的成本是多少?我想在每个注册表中都会创建一个NFA。据我所知,NFA的创建是不平凡的

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

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

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

查看
RegexOptions
enum也很有价值,因为其他标志有时可能会有所帮助。

与我典型的自我主义有一个罕见的不同,我在这个答案上有点颠倒了自己

我最初的答案(保留在下面)是基于对.NET framework 1.1版的检查。这是非常可耻的,因为在我回答时.NET2.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);
}
public static bool IsMatch(string input, string pattern){
    return new Regex(pattern).IsMatch(input);
}
这里的显著区别是,第三个参数是little
true
。它对应于名为“useCache”的参数。如果为true,则在第二次和后续使用时从缓存中检索解析的树

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

在某些情况下,这20%的减速可能仍然很明显。如果您发现自己正在重新生成数亿个字符串,那么您可能希望尽可能采取每一步来提高效率。但我敢打赌,99%的时间里,你使用一个特定的正则表达式的次数不会超过几次,而你在静态方法中损失的额外毫秒也不会太明显

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

我的旧答案如下:


静态
IsMatch
功能定义如下:

public static bool IsMatch(string input, string pattern){
    return new Regex(pattern, RegexOptions.None, true).IsMatch(input);
}
public static bool IsMatch(string input, string pattern){
    return new Regex(pattern).IsMatch(input);
}
而且,是的,
Regex
对象的初始化并不简单。您应该使用静态
IsMatch
(或任何其他静态
Regex
函数)作为仅使用一次的模式的快捷方式。如果要重用该模式,那么也应该重用
Regex
对象

至于是否应该按照Jon Skeet的建议指定
RegexOptions.Compiled
,那是另一回事了。答案是:视情况而定。对于简单的模式或仅使用过几次的模式,使用非编译实例可能会更快。在做出决定之前,你应该先确定你的个人资料。编译正则表达式对象的成本确实相当大,可能不值得


以以下为例:

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);
const int count=10000;
字符串模式=“^[a-z]+[0-9]+$”;
字符串输入=“abc123”;
秒表sw=Stopwatch.StartNew();
for(int i=0;i
如清单所示,当计数=10000时,第二个输出速度最快。将
count
增加到
100000
,编译后的版本将获胜。

我建议您阅读编译正则表达式

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

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

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

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

有许多事情会影响使用正则表达式的性能。归根结底,找出你的处境中表现最好的唯一方法是测量,尽可能地使用现实的处境

MSDN上正则表达式对象的第页介绍了这一点。总之,它说

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

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


  • 对于我机器上的.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”的构造函数参数。所有的正则表达式构造函数最终都通过这个链接,静态函数直接调用这个,并传入“true”

    你在BCL博客上读到了更多关于optimi的文章