我正在做一些事情,我意识到我想要在一个字符串中找到多少个/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;
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;
}
如果你使用的是。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次,因此在现实世界中您不太可能注意到太多差异。)
var conditionalStatement = conditionSetting.Value;
//order of replace matters, remove == before =, incase of ===
conditionalStatement = conditionalStatement.Replace("==", "~").Replace("!=", "~").Replace('=', '~').Replace('!', '~').Replace('>', '~').Replace('<', '~').Replace(">=", "~").Replace("<=", "~");
var listOfValidConditions = new List<string>() { "!=", "==", ">", "<", ">=", "<=" };
if (conditionalStatement.Count(x => x == '~') != 1)
{
result.InvalidFieldList.Add(new KeyFieldData(batch.DECurrentField, "The IsDoubleKeyCondition does not contain a supported conditional statement. Contact System Administrator."));
result.Status = ValidatorStatus.Fail;
return result;
}
需要做一些类似于从字符串测试条件语句的事情。
用单个字符替换我正在寻找的内容,并计算单个字符的实例数。
显然,在发生这种情况之前,您需要检查您正在使用的单个字符是否存在于字符串中,以避免错误计数。