我正在做一些事情,我意识到我想要在一个字符串中找到多少个/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;
对于任何想要使用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;
}
}
Split (may)胜过IndexOf(用于字符串)。
上面的基准测试似乎表明Richard Watson是最快的字符串,这是错误的(可能差异来自我们的测试数据,但由于下面的原因,它看起来很奇怪)。
如果我们更深入地研究这些方法在.NET中的实现(对于Luke H, Richard Watson方法),
IndexOf取决于区域性,它将尝试检索/创建ReadOnlySpan,检查是否必须忽略大小写等。最后执行不安全/本机调用。
Split能够处理多个分隔符,并有一些StringSplitOptions
并且必须创建字符串[]数组并用分割结果填充它(所以做一些子字符串)。根据字符串出现的数量,Split可能比IndexOf更快。
顺便说一下,我做了一个简化版本的IndexOf(它可以更快,如果我使用指针和不安全,但不勾选应该是ok的大多数),它至少快了4个数量级。
基准测试(来源GitHub)
通过搜索一个常见的单词(the)或一个小句子
莎士比亚,理查三世。
Method |
Mean |
Error |
StdDev |
Ratio |
Richard_LongInLong |
67.721 us |
1.0278 us |
0.9614 us |
1.00 |
Luke_LongInLong |
1.960 us |
0.0381 us |
0.0637 us |
0.03 |
Fab_LongInLong |
1.198 us |
0.0160 us |
0.0142 us |
0.02 |
-------------------- |
-----------: |
----------: |
----------: |
------: |
Richard_ShortInLong |
104.771 us |
2.8117 us |
7.9304 us |
1.00 |
Luke_ShortInLong |
2.971 us |
0.0594 us |
0.0813 us |
0.03 |
Fab_ShortInLong |
2.206 us |
0.0419 us |
0.0411 us |
0.02 |
--------------------- |
----------: |
---------: |
---------: |
------: |
Richard_ShortInShort |
115.53 ns |
1.359 ns |
1.135 ns |
1.00 |
Luke_ShortInShort |
52.46 ns |
0.970 ns |
0.908 ns |
0.45 |
Fab_ShortInShort |
28.47 ns |
0.552 ns |
0.542 ns |
0.25 |
public int GetOccurrences(string input, string needle)
{
int count = 0;
unchecked
{
if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(needle))
{
return 0;
}
for (var i = 0; i < input.Length - needle.Length + 1; i++)
{
var c = input[i];
if (c == needle[0])
{
for (var index = 0; index < needle.Length; index++)
{
c = input[i + index];
var n = needle[index];
if (c != n)
{
break;
}
else if (index == needle.Length - 1)
{
count++;
}
}
}
}
}
return count;
}