.net-Regex.IsMatch与string。包含

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

Regex.IsMatch(Message, "1000")

VS

Message.Contains("1000")

有什么情况比别人更好吗?

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

Pradeep asked 2020-08-10T03:53:16Z
6个解决方案
43 votes

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

正则表达式具有与之相关的一定数量的开销(表达式解析,编译,执行等),而像String.Contains这样的简单方法根本没有正则表达式,这就是为什么String.Contains在诸如此类的示例中会胜过正则表达式。

Andrew Hare answered 2020-08-10T03:53:27Z
36 votes

将其与已编译的正则表达式进行比较时,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;
  }
}
user279470 answered 2020-08-10T03:53:51Z
7 votes

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

String.Contains()的实现最终将调用本机方法IndexOfString(),该实现仅由Microsoft知道。 但是,实现此方法的一个好的算法是使用所谓的Knuth-Morris-Pratt算法。 此算法的复杂度为O(m + n),其中m是要搜索的字符串的长度,n是要搜索的字符串的长度,这使其成为一种非常有效的算法。

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

如果您真的担心搜索速度,克里斯蒂安·查拉斯(Christian Charras)和蒂埃里·勒克罗(Thierry Lecroq)在鲁昂大学(Universitéde Rouen)拥有大量有关精确字符串匹配算法的材料。

Martin Liversage answered 2020-08-10T03:54:26Z
6 votes

@ user279470我一直在寻找一种有效的方法来计算单词的数量,只是为了好玩而已。 我给了它OpenOffice Thesaurus dat文件以进行迭代。 总字数为1575423。

现在,我的最终目标没有使用contains,但是有趣的是看到了可以更快地调用regex的不同方法。 我创建了一些其他方法来比较regex的实例使用和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
spring1975 answered 2020-08-10T03:55:08Z
3 votes

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

在我的用例中,我想用一些OR运算符检查一个简单的Regex是否有4个值,而不是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());
        }
    }
}
gb2d answered 2020-08-10T03:55:37Z
0 votes

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

Matthew Flaschen answered 2020-08-10T03:55:57Z
translate from https://stackoverflow.com:/questions/2962670/regex-ismatch-vs-string-contains