Regex.IsMatch vs string.Contains

时间:2010-06-03 00:51:19

标签: .net regex string

这两个等效表达式的速度/内存使用是否有任何区别:

Regex.IsMatch(Message, "1000")

Vs的

Message.Contains("1000")

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

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

7 个答案:

答案 0 :(得分:42)

对于简单的情况,String.Contains会为您提供更好的效果,但String.Contains不允许您进行复杂的模式匹配。将String.Contains用于非模式匹配方案(如示例中的方案),并在需要进行更复杂模式匹配的方案中使用正则表达式。

正则表达式有一定的开销(表达式解析,编译,执行等)与String.Contains这样的简单方法根本没有,这就是为什么String.Contains会胜过的原因像你这样的例子中的正则表达式。

答案 1 :(得分:33)

将它与compiled regular expression进行比较时,

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;
  }
}

答案 2 :(得分:7)

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

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

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

如果你真的关心搜索速度,Christian Charras和Thierry Lecroq在鲁昂大学有很多关于exact string matching algorithms的材料。

答案 3 :(得分:6)

@ user279470我一直在寻找一种有效的方式来计算单词以获得乐趣并遇到this。我给了它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;
    }
}
  • regExCompileTimer.ElapsedMilliseconds 11787
  • regExStaticTimer.ElapsedMilliseconds 12300
  • regExInstanceTimer.ElapsedMilliseconds 13925
  • ContainsTimer.ElapsedMilliseconds 1074

答案 4 :(得分:2)

我自己的替补标记似乎与user279470的基准测试结果相矛盾。

在我的用例中,我想检查一个简单的Regex,其中包含4个值的OR运算符,而不是4 x String.Contains()

即使有4 x String.Contains(),我发现String.Contains()的速度提高了5倍。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Text.RegularExpressions;

namespace App.Tests.Performance
{
    [TestClass]
    public class PerformanceTesting
    {
        private static Random random = new Random();

        [TestMethod]
        public void RegexVsMultipleContains()
        {
            var matchRegex = new Regex("INFO|WARN|ERROR|FATAL");

            var testStrings = new List<string>();

            int iterator = 1000000 / 4; // div 4 for each of log levels checked

            for (int i = 0; i < iterator; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    var simulatedTestString = RandomString(50);

                    if (j == 0)
                    {
                        simulatedTestString += "INFO";
                    }
                    else if (j == 1)
                    {
                        simulatedTestString += "WARN";
                    }
                    else if (j == 2)
                    {
                        simulatedTestString += "ERROR";
                    }
                    else if (j == 3)
                    {
                        simulatedTestString += "FATAL";
                    }

                    simulatedTestString += RandomString(50);

                    testStrings.Add(simulatedTestString);
                }
            }

            int cnt;
            Stopwatch sw;

            //////////////////////////////////////////
            // Multiple contains test
            //////////////////////////////////////////

            cnt = 0;
            sw = new Stopwatch();

            sw.Start();

            for (int i = 0; i < testStrings.Count; i++)
            {
                bool isMatch = testStrings[i].Contains("INFO") || testStrings[i].Contains("WARN") || testStrings[i].Contains("ERROR") || testStrings[i].Contains("FATAL");

                if (isMatch)
                {
                    cnt += 1;
                }
            }

            sw.Stop();

            Console.WriteLine("MULTIPLE CONTAINS: " + cnt + " " + sw.ElapsedMilliseconds);

            //////////////////////////////////////////
            // Multiple contains using list test
            //////////////////////////////////////////

            cnt = 0;
            sw = new Stopwatch();

            sw.Start();

            var searchStringList = new List<string> { "INFO", "WARN", "ERROR", "FATAL" };

            for (int i = 0; i < testStrings.Count; i++)
            {
                bool isMatch = searchStringList.Any(x => testStrings[i].Contains(x));

                if (isMatch)
                {
                    cnt += 1;
                }
            }

            sw.Stop();

            Console.WriteLine("MULTIPLE CONTAINS USING LIST: " + cnt + " " + sw.ElapsedMilliseconds);

            //////////////////////////////////////////
            // Regex test
            ////////////////////////////////////////// 

            cnt = 0;
            sw = new Stopwatch();

            sw.Start();

            for (int i = 0; i < testStrings.Count; i++)
            {
                bool isMatch = matchRegex.IsMatch(testStrings[i]);

                if (isMatch)
                {
                    cnt += 1;
                }
            }

            sw.Stop();

            Console.WriteLine("REGEX: " + cnt + " " + sw.ElapsedMilliseconds);
        }

        public static string RandomString(int length)
        {
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

            return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
        }
    }
}

答案 5 :(得分:0)

是的,对于这个任务,string.Contains几乎肯定会更快并且使用更少的内存。当然,这里没有理由使用正则表达式。

答案 6 :(得分:0)

正则表达式匹配由.NET Framework的正则表达式引擎处理。以下是msdn article中的部分,准确说明了何时使用Regex与String搜索和替换功能:

String类包含许多字符串搜索和替换方法,当您要在较大的字符串中找到原义字符串时,可以使用这些方法。 正则表达式在您要在较大的字符串中定位多个子字符串之一时,或者在要标识字符串中的模式时最有用,如以下示例所示。

有两个示例在文章中对此进行了说明。