我正在做一些事情,我意识到我想要在一个字符串中找到多少个/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;

当前回答

int count = new Regex(Regex.Escape(needle)).Matches(haystack).Count;

其他回答

我做了一些研究,发现理查德·沃森的解决方案在大多数情况下是最快的。这是文章中每个解决方案的结果表(除了那些使用Regex的,因为它在解析“test{test”这样的字符串时抛出异常)

    Name      | Short/char |  Long/char | Short/short| Long/short |  Long/long |
    Inspite   |         134|        1853|          95|        1146|         671|
    LukeH_1   |         346|        4490|         N/A|         N/A|         N/A|
    LukeH_2   |         152|        1569|         197|        2425|        2171|
Bobwienholt   |         230|        3269|         N/A|         N/A|         N/A|
Richard Watson|          33|         298|         146|         737|         543|
StefanosKargas|         N/A|         N/A|         681|       11884|       12486|

可以看到,在短字符串(10-50个字符)中查找短子字符串(1-5个字符)的出现次数时,首选原算法。

同样,对于多字符子字符串,您应该使用以下代码(基于Richard Watson的解决方案)

int count = 0, n = 0;

if(substring != "")
{
    while ((n = source.IndexOf(substring, n, StringComparison.InvariantCulture)) != -1)
    {
        n += substring.Length;
        ++count;
    }
}

**计数字符或字符串**

 string st = "asdfasdfasdfsadfasdf/asdfasdfas/dfsdfsdafsdfsd/fsadfasdf/dff";
        int count = 0;
        int location = 0;
       
        while (st.IndexOf("/", location + 1) > 0)
        {
                count++;
                location = st.IndexOf("/", location + 1);
        }
        MessageBox.Show(count.ToString());

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;
}

编辑:

source.Split('/').Length-1

查找字符计数与查找字符串计数有很大不同。另外,这也取决于你是否想要检查不止一个。如果你想检查各种不同的字符计数,像这样的东西可以工作:

var charCounts =
   haystack
   .GroupBy(c => c)
   .ToDictionary(g => g.Key, g => g.Count());

var needleCount = charCounts.ContainsKey(needle) ? charCounts[needle] : 0;

注1:分组到字典中非常有用,因此为它编写GroupToDictionary扩展方法非常有意义。

注意2:拥有自己的字典实现也很有用,它允许默认值,然后您可以自动为不存在的键获取0。