Regex.IsMatch vs string.Contains

Pra*_*eep 42 .net regex string

这两个等效表达式的速度/内存使用有什么不同:

Regex.IsMatch(Message, "1000")
Run Code Online (Sandbox Code Playgroud)

VS

Message.Contains("1000")
Run Code Online (Sandbox Code Playgroud)

任何一个比其他更好的情况?

这个问题的上下文如下:我正在对包含Regex表达式的遗留代码进行一些更改,以查找字符串是否包含在另一个字符串中.作为遗留代码,我没有对此进行任何更改,在代码审查中有人建议Regex.IsMatch应该替换为string.Contains.所以我想知道改变是否值得.

And*_*are 43

对于简单的情况,String.Contains将为您提供更好的性能,但String.Contains不允许您进行复杂的模式匹配.使用String.Contains非模式匹配的情况(像在你的例子),并使用正则表达式中,你需要做更复杂的模式匹配的情况.

正则表达式有一定的开销与它相关联(表达式解析,编译,执行等),简单的方法就像一个简单的方法String.Contains没有,这就是为什么String.Contains在像你这样的例子中胜过正则表达式.


use*_*470 36

String.Contains将它与编译的正则表达式进行比较时,速度会变慢.相当慢,甚至!

您可以测试运行此基准测试:

class Program
{
  public static int FoundString;
  public static int FoundRegex;

  static void DoLoop(bool show)
  {
    const string path = "C:\\file.txt";
    const int iterations = 1000000;
    var content = File.ReadAllText(path);

    const string searchString = "this exists in file";
    var searchRegex = new Regex("this exists in file");

    var containsTimer = Stopwatch.StartNew();
    for (var i = 0; i < iterations; i++)
    {
      if (content.Contains(searchString))
      {
        FoundString++;
      }
    }
    containsTimer.Stop();

    var regexTimer = Stopwatch.StartNew();
    for (var i = 0; i < iterations; i++)
    {
      if (searchRegex.IsMatch(content))
      {
        FoundRegex++;
      }
    }
    regexTimer.Stop();

    if (!show) return;

    Console.WriteLine("FoundString: {0}", FoundString);
    Console.WriteLine("FoundRegex: {0}", FoundRegex);
    Console.WriteLine("containsTimer: {0}", containsTimer.ElapsedMilliseconds);
    Console.WriteLine("regexTimer: {0}", regexTimer.ElapsedMilliseconds);

    Console.ReadLine();
  }

  static void Main(string[] args)
  {
    DoLoop(false);
    DoLoop(true);
    return;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 在60kb的随机EDIFACT INVRP文件上运行它,其中"这存在于文件中"填充在中途:containsTimer:84925 regexTimer:10633 (3认同)
  • 虽然它不是String.Contains(),我只是修改了搜索和在我的程序使用正则表达式编译对象,而不是"Value.ToString.IndexOf(SearchString在,StringComparison.CurrentCultureIgnoreCase)"替换功能.我使用> 44,000行DataGridView(1,921次替换)的替换所有测试从大约7.5分钟到大约30秒. (3认同)
  • 内容。包含胜利。因为`new Regex("this exists in file")` != `content.Contains(searchString)`...但是`new Regex(".+this exists in file.+")`。 (2认同)

Mar*_*age 7

要确定哪个是最快的,您将需要对自己的系统进行基准测试.但是,正则表达式很复杂,而且String.Contains()很有可能是最快的,在您的情况下也是最简单的解决方案.

String.Contains()最终的实现将调用本机方法 IndexOfString(),并且只有Microsoft知道它的实现.然而,用于实现该方法的良好算法使用所谓的Knuth-Morris-Pratt算法.这个算法的复杂性是O(m + n),其中m是你要搜索的字符串的长度,n是你正在搜索的字符串的长度,使它成为一个非常有效的算法.

实际上,使用正则表达式的搜索效率可以是低O(n),具体取决于实现,因此在某些情况下它仍然具有竞争性.只有基准测试才能确定这一点.

如果你真的关心搜索速度,Christian Charras和Thierry Lecroq 在UniversitédeRouen 有很多关于精确字符串匹配算法的资料.


小智 6

@ user279470我一直在寻找一种有效的方式来计算单词以获得乐趣,并且遇到了这个问题.我给了它OpenOffice Thesaurus dat文件来迭代.总字数达到1575423.

现在,我的最终目标没有用于包含,但有趣的是看到你可以调用正则表达式的不同方法,使其更快.我创建了一些其他方法来比较正则表达式的实例使用和静态使用与RegexOptions.compiled.

public static class WordCount
{
    /// <summary>
    /// Count words with instaniated Regex.
    /// </summary>
    public static int CountWords4(string s)
    {
        Regex r = new Regex(@"[\S]+");
        MatchCollection collection = r.Matches(s);
        return collection.Count;
    }
    /// <summary>
    /// Count words with static compiled Regex.
    /// </summary>
    public static int CountWords1(string s)
    {
        MatchCollection collection = Regex.Matches(s, @"[\S]+", RegexOptions.Compiled);
        return collection.Count;
    }
    /// <summary>
    /// Count words with static Regex.
    /// </summary>
    public static int CountWords3(string s)
    {
        MatchCollection collection = Regex.Matches(s, @"[\S]+");
        return collection.Count;
    }

    /// <summary>
    /// Count word with loop and character tests.
    /// </summary>
    public static int CountWords2(string s)
    {
        int c = 0;
        for (int i = 1; i < s.Length; i++)
        {
            if (char.IsWhiteSpace(s[i - 1]) == true)
            {
                if (char.IsLetterOrDigit(s[i]) == true ||
                    char.IsPunctuation(s[i]))
                {
                    c++;
                }
            }
        }
        if (s.Length > 2)
        {
            c++;
        }
        return c;
    }
}
Run Code Online (Sandbox Code Playgroud)
  • regExCompileTimer.ElapsedMilliseconds 11787
  • regExStaticTimer.ElapsedMilliseconds 12300
  • regExInstanceTimer.ElapsedMilliseconds 13925
  • ContainsTimer.ElapsedMilliseconds 1074