这两个等效表达式的速度/内存使用是否有任何区别:
Regex.IsMatch(Message, "1000")
Vs的
Message.Contains("1000")
任何一个人比其他人好的情况?
这个问题的背景如下: 我正在对包含Regex表达式的遗留代码进行一些更改,以查找字符串是否包含在另一个字符串中。作为遗留代码,我没有对此进行任何更改,在代码审查中有人建议Regex.IsMatch应该替换为string.Contains。所以我想知道改变是否值得。
答案 0 :(得分:42)
对于简单的情况,String.Contains
会为您提供更好的效果,但String.Contains
不允许您进行复杂的模式匹配。将String.Contains
用于非模式匹配方案(如示例中的方案),并在需要进行更复杂模式匹配的方案中使用正则表达式。
正则表达式有一定的开销(表达式解析,编译,执行等)与String.Contains
这样的简单方法根本没有,这就是为什么String.Contains
会胜过的原因像你这样的例子中的正则表达式。
答案 1 :(得分:33)
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;
}
}
答案 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类包含许多字符串搜索和替换方法,当您要在较大的字符串中找到原义字符串时,可以使用这些方法。 正则表达式在您要在较大的字符串中定位多个子字符串之一时,或者在要标识字符串中的模式时最有用,如以下示例所示。
有两个示例在文章中对此进行了说明。