Regex.IsMatch против строки. Содержит - PullRequest
41 голосов
/ 03 июня 2010

Есть ли разница в скорости / использовании памяти для этих двух эквивалентных выражений:

Regex.IsMatch(Message, "1000")

Vs

Message.Contains("1000")

В каких ситуациях один лучше других?

Контекст этого вопроса следующий: Я вносил некоторые изменения в унаследованный код, который содержал выражение Regex, чтобы найти, содержится ли строка в другой строке. Будучи устаревшим кодом, я не вносил в него никаких изменений, и в обзоре кода кто-то предлагал заменить Regex.IsMatch на string.Contains. Поэтому мне было интересно, стоило ли это изменение сделать.

Ответы [ 6 ]

42 голосов
/ 03 июня 2010

Для простых случаев String.Contains даст вам лучшую производительность, но String.Contains не позволит вам выполнить сложное сопоставление с образцом. Используйте String.Contains для сценариев сопоставления не с шаблонами (как в вашем примере) и используйте регулярные выражения для сценариев, в которых вам нужно выполнить более сложное сопоставление с шаблонами.

С регулярным выражением связаны определенные накладные расходы (разбор выражений, компиляция, выполнение и т. Д.), Которого у простого метода, такого как String.Contains, просто нет, поэтому String.Contains будет превосходить регулярное выражение примеры, подобные твоему.

34 голосов
/ 01 сентября 2010

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;
  }
}
7 голосов
/ 06 июля 2010

Чтобы определить, какой из них самый быстрый, вам нужно будет протестировать свою собственную систему. Однако регулярные выражения сложны, и есть вероятность, что String.Contains() будет самым быстрым, а в вашем случае - и самым простым решением.

Реализация String.Contains() в конечном итоге вызовет собственный метод IndexOfString(), а реализация этого метода известна только Microsoft. Тем не менее, хороший алгоритм для реализации этого метода использует так называемый алгоритм Кнута-Морриса-Пратта . Сложность этого алгоритма составляет O (m + n) , где m - длина искомой строки, а n - длина строки. Вы ищете, чтобы сделать его очень эффективным алгоритмом.

На самом деле эффективность поиска с использованием регулярных выражений может быть низкой O (n) в зависимости от реализации, поэтому в некоторых ситуациях она все еще может быть конкурентной. Только эталон сможет определить это.

Если вы действительно обеспокоены скоростью поиска, у Кристиана Чарраса и Тьерри Лекрока есть много материала о точных алгоритмах сопоставления строк в Университете Руана.

6 голосов
/ 25 февраля 2011

@ user279470 Я искал эффективный способ подсчета слов просто для удовольствия и наткнулся на это . Я дал ему файл данных OpenOffice Thesaurus для итерации. Общее количество слов составило 1575423.

Теперь, моей конечной целью не было использования содержимого, но было интересно увидеть различные способы, которые можно назвать регулярным выражением, которые делают его еще быстрее. Я создал несколько других методов для сравнения использования экземпляра 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
3 голосов
/ 24 ноября 2016

Похоже, что мои собственные результаты тестов противоречат результатам теста user279470.

В моем случае использования я хотел проверить простое регулярное выражение с некоторыми операторами ИЛИ для 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());
        }
    }
}
0 голосов
/ 03 июня 2010

Да, для этой задачи string.Contains почти наверняка будет быстрее и будет использовать меньше памяти. И, конечно же, здесь нет причин использовать регулярные выражения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...