String.Contains如何工作?

可能重复:
什么算法.Net用于搜索字符串中的模式?

我的程序中有一个循环从文件中获取一行。 然后检查该行是否包含字符串

if(line.Contains("String")) { //Do other stuff } 

文件中有超过200万行,所以如果我可以将速度加快1/10毫秒,那么每次运行会节省3分钟以上。

所以…假设一条线长1000个字符,是否更快找到一个短或长的字符串,或者它没有区别?

 line.Contains("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 

要么

 line.Contains("ABCDEFG") 

先感谢您。

String.Contains()遵循一条曲折的路线,通过System.Globalization.CompareInfo进入CLR和NLS支持子系统,在那里我彻底迷失了。 这包含高度优化的代码和令人印象深刻 更快地完成它的唯一方法是通过pingvvrt.dll中提供的标准CRT函数wcsstr

  [DllImport("msvcrt.dll", CharSet = CharSet.Unicode)] private static extern IntPtr wcsstr(string toSearch, string toFind); 

如果找不到该字符串,则返回IntPtr.Zero。 我做了一些测量,使用String.IndexOf()而不是Contains()来测试各种字符串比较选项。 所有时间都以纳秒为单位,在60个字符的字符串中搜索7个字符的字符串。 由于字符串不存在,因此测量最坏情况。 使用20个样本中的最短时间:

 StringComparison.Ordinal (same as Contains) : 245 nanoseconds StringComparison.OrdinalIgnoreCase : 327 StringComparison.InvariantCulture : 251 StringComparison.InvariantCultureIgnoreCase : 327 StringComparison.CurrentCulture : 275 StringComparison.CurrentCultureIgnoreCase : 340 wcsstr : 213 

非常令人印象深刻的数字,与您期望这些function所需要的相同。 wcsstr()函数与String.Compare()进行相同的序数比较。 由于CPU缓存局部性的影响,实际性能不太可能接近这些测量,因此它仅快13%,在统计上无显着改善。 我只能得出结论,你的速度和你想象的一样快。 wcsstr的微小改进是否值得,取决于你。

“通常,当搜索的密钥变得更长时,算法变得更快”

http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

如果.NET String.Contains使用Boyer-Moore算法 ,则搜索更长的字符串会更快。

我可以建议,如果你正在阅读一个分隔文件,例如每行是一系列用逗号分隔的文本字段,你可以节省一些搜索时间,如果你知道它不能在行之前从行中的位置0搜索例如,角色40。

在分隔符字符上使用String Spilled函数分割一条线是很常见的,这会返回一个字符串数组。 然后,您只能在值可能出现的字段内搜索。 这也会更快。

在提高性能方面,您需要确保您想要改进的内容实际上是导致瓶颈的原因。 我将首先分析代码中各个部分的性能,然后找出哪个部分引入了最大的瓶颈。

乍一看,我看到这个过程的三个主要组成部分值得分析:

  • 循环遍历文件的全部内容(这可能包括也可能不包括文件IO注意事项,您可能希望单独测试)。
  • 检查文件中每一行的String.Contains()
  • 当有比赛时“Do Stuff”

虽然那里有很棒的商业分析器,但您可以在代码中使用简单的计时器(如System.Diagnostics.Stopwatch ),或者,如果过程非常长,只需使用watch来测量时间。

测量以下各项的时间。

  1. 测量只需查看整个文件而无需执行任何其他操作所需的时间。 这会隔离您的循环和IO代码,以便您可以看到它的执行情况。
  2. 接下来,仅添加字符串比较( String.Contains )并测量添加此字符串String.Contains的总时间。
  3. 最后,添加“do stuff”代码并使用此添加来衡量总时间。

您现在可以比较每个组件中添加的成本,以确定该组件的成本以及是否需要对其进行改进。 例如,假设您录制了以下时间:

 Test Total Time Cost (Difference) ============================================= Do Nothing 0s 0s Loop Only 100s 100s Add Comparison 105s 5s Add Do Stuff 130s 25s 

看看那些(假的)数字,这个过程中最昂贵的部分是循环和IO代码,所以这就是我开始尝试提高性能的地方。 由于“Do Stuff”部分在整个执行时间上增加了25秒,我会看看旁边的代码,看看是否有什么我可以改进的。 最后,我会看一下字符串比较。

当然,我提供的时间测量值是虚构的,但您可以在应用程序中对性能分析应用相同的步骤。 关键是确定最大的成本,并尝试先减少成本。

令我惊讶的是,编译的Regex实际上比Contains快得多。 当然,如果您多次搜索相同的字符串,编译的成本是值得的。 但如果是这样,它的速度要快两倍以上。 亲自尝试一下:

 static void Test() { var random = new Random(10); var alphabet = "abcdefghijklmnopqrstuvwxyz"; var content = new String((from x in Enumerable.Range(0, 10000000) select a[random.Next(0, a.Length)]).ToArray()); var searchString = content.Substring(5000000, 4096); var regex = new Regex(searchString); var sw = Stopwatch.StartNew(); for (int i = 0; i < 1000; i++) { if (!regex.IsMatch(content)) { throw new Exception(); } } sw.Stop(); Console.WriteLine("Regex: " + sw.Elapsed); sw.Restart(); for (int i = 0; i < 1000; i++) { if (!content.Contains(searchString)) { throw new Exception(); } } sw.Stop(); Console.WriteLine("String.Contains: " + sw.Elapsed); } 

我仍然没有弄清楚它是如何快速的,看着编译的程序集,它是一个混乱的switch语句混乱。 但它很快, 非常快。

当且仅当此字符串包含指定的char值序列时,String.Contains方法才返回true。

它主要用于检查字符串中的子字符串。

http://csharp.net-informations.com/string/csharp-string-contains.htm

像所有的字符串搜索方法(我认为)一样,包含最终会导致外部方法InternalFindNLSStringEx – 无论如何,它都是相当不可思议的。