我正在做一些事情,我意识到我想要在一个字符串中找到多少个/s,然后我突然想到,有几种方法可以做到这一点,但不能决定哪种是最好的(或最简单的)。
目前我想说的是:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
但我一点都不喜欢,有人愿意吗?
我并不想为此挖掘出正则表达式,对吧?
我知道我的字符串将包含我要搜索的项,所以你可以假设…
当然对于长度为> 1的字符串,
string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;
我最初的想法是这样的:
public static int CountOccurrences(string original, string substring)
{
if (string.IsNullOrEmpty(substring))
return 0;
if (substring.Length == 1)
return CountOccurrences(original, substring[0]);
if (string.IsNullOrEmpty(original) ||
substring.Length > original.Length)
return 0;
int substringCount = 0;
for (int charIndex = 0; charIndex < original.Length; charIndex++)
{
for (int subCharIndex = 0, secondaryCharIndex = charIndex; subCharIndex < substring.Length && secondaryCharIndex < original.Length; subCharIndex++, secondaryCharIndex++)
{
if (substring[subCharIndex] != original[secondaryCharIndex])
goto continueOuter;
}
if (charIndex + substring.Length > original.Length)
break;
charIndex += substring.Length - 1;
substringCount++;
continueOuter:
;
}
return substringCount;
}
public static int CountOccurrences(string original, char @char)
{
if (string.IsNullOrEmpty(original))
return 0;
int substringCount = 0;
for (int charIndex = 0; charIndex < original.Length; charIndex++)
if (@char == original[charIndex])
substringCount++;
return substringCount;
}
使用替换和除法的大海捞针方法产生21秒以上,而这需要大约15.2秒。
在添加位后进行编辑,这将添加子字符串。长度- 1到charIndex(就像它应该的那样),它在11.6秒。
编辑2:我使用了一个有26个双字符字符串的字符串,这里是更新到相同示例文本的时间:
大海捞针(OP版本):7.8秒
建议的机制:4.6秒。
编辑3:添加单个字符的大小写,它变成了1.2秒。
编辑4:作为上下文:使用了5000万次迭代。
如果你使用的是。net 3.5,你可以用LINQ在一行代码中完成:
int count = source.Count(f => f == '/');
如果你不想使用LINQ,你可以用:
int count = source.Split('/').Length - 1;
您可能会惊讶地发现,您原来的技术似乎比这两种方法都快30% !我刚刚用“/once/upon/a/time/”做了一个快速的基准测试,结果如下:
你的原稿= 12s
源。计数= 19秒
源。分裂= 17秒
Foreach(来自bobwienholt的答案)= 10s
(迭代次数为50,000,000次,因此在现实世界中您不太可能注意到太多差异。)
对于任何想要使用String扩展方法的人,
以下是我使用的基于张贴的最好的答案:
public static class StringExtension
{
/// <summary> Returns the number of occurences of a string within a string, optional comparison allows case and culture control. </summary>
public static int Occurrences(this System.String input, string value, StringComparison stringComparisonType = StringComparison.Ordinal)
{
if (String.IsNullOrEmpty(value)) return 0;
int count = 0;
int position = 0;
while ((position = input.IndexOf(value, position, stringComparisonType)) != -1)
{
position += value.Length;
count += 1;
}
return count;
}
/// <summary> Returns the number of occurences of a single character within a string. </summary>
public static int Occurrences(this System.String input, char value)
{
int count = 0;
foreach (char c in input) if (c == value) count += 1;
return count;
}
}
如果你看看这个网页,有15种不同的方法进行了基准测试,包括使用并行循环。
最快的方法似乎是使用单线程for循环(如果您的。net版本< 4.0)或并行。for循环(如果使用。net > 4.0进行数千次检查)。
假设“ss”是你的搜索字符串,“ch”是你的字符数组(如果你有一个以上的字符你正在寻找),下面是代码的基本要点,有最快的运行时间单线程:
for (int x = 0; x < ss.Length; x++)
{
for (int y = 0; y < ch.Length; y++)
{
for (int a = 0; a < ss[x].Length; a++ )
{
if (ss[x][a] == ch[y])
//it's found. DO what you need to here.
}
}
}
还提供了基准测试源代码,以便您可以运行自己的测试。