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

当前回答

str="aaabbbbjjja";
int count = 0;
int size = str.Length;

string[] strarray = new string[size];
for (int i = 0; i < str.Length; i++)
{
    strarray[i] = str.Substring(i, 1);
}
Array.Sort(strarray);
str = "";
for (int i = 0; i < strarray.Length - 1; i++)
{

    if (strarray[i] == strarray[i + 1])
    {

        count++;
    }
    else
    {
        count++;
        str = str + strarray[i] + count;
        count = 0;
    }

}
count++;
str = str + strarray[strarray.Length - 1] + count;

这是用来计算字符出现次数的。本例的输出为"a4b4j3"

其他回答

string Name = "Very good nice one is very good but is very good nice one this is called the term";
bool valid=true;
int count = 0;
int k=0;
int m = 0;
while (valid)
{
    k = Name.Substring(m,Name.Length-m).IndexOf("good");
    if (k != -1)
    {
        count++;
        m = m + k + 4;
    }
    else
        valid = false;
}
Console.WriteLine(count + " Times accures");

从。Net 5 (Net core 2.1+和NetStandard 2.1)开始,我们有了一个新的迭代速度之王。

“跨度<T>”https://learn.microsoft.com/en-us/dotnet/api/system.span-1?view=net-5.0

String有一个内置成员,返回Span<Char>

int count = 0;
foreach( var c in source.AsSpan())
{
    if (c == '/')
        count++;
}

我的测试显示比直刺快62%我还比较了Span<T>[I]上的for()循环,以及这里发布的其他一些内容。注意,String上的反向for()迭代现在似乎比直接foreach运行得慢。

Starting test, 10000000 iterations
(base) foreach =   673 ms

fastest to slowest
foreach Span =   252 ms   62.6%
  Span [i--] =   282 ms   58.1%
  Span [i++] =   402 ms   40.3%
   for [i++] =   454 ms   32.5%
   for [i--] =   867 ms  -28.8%
     Replace =  1905 ms -183.1%
       Split =  2109 ms -213.4%
  Linq.Count =  3797 ms -464.2%

更新:2021年12月,Visual Studio 2022, .NET 5和6

.NET 5
Starting test, 100000000 iterations set
(base) foreach =  7658 ms
fastest to slowest
  foreach Span =   3710 ms     51.6%
    Span [i--] =   3745 ms     51.1%
    Span [i++] =   3932 ms     48.7%
     for [i++] =   4593 ms     40.0%
     for [i--] =   7042 ms      8.0%
(base) foreach =   7658 ms      0.0%
       Replace =  18641 ms   -143.4%
         Split =  21469 ms   -180.3%
          Linq =  39726 ms   -418.8%
Regex Compiled = 128422 ms -1,577.0%
         Regex = 179603 ms -2,245.3%
         
         
.NET 6
Starting test, 100000000 iterations set
(base) foreach =  7343 ms
fastest to slowest
  foreach Span =   2918 ms     60.3%
     for [i++] =   2945 ms     59.9%
    Span [i++] =   3105 ms     57.7%
    Span [i--] =   5076 ms     30.9%
(base) foreach =   7343 ms      0.0%
     for [i--] =   8645 ms    -17.7%
       Replace =  18307 ms   -149.3%
         Split =  21440 ms   -192.0%
          Linq =  39354 ms   -435.9%
Regex Compiled = 114178 ms -1,454.9%
         Regex = 186493 ms -2,439.7%

我添加了更多的循环,并加入了RegEx,这样我们就可以看到在大量迭代中使用它是一场灾难。 我认为for(++)循环比较可能已经在。net 6中进行了优化,以便在内部使用Span -因为它与foreach Span的速度几乎相同。

代码链接

string source = "/once/upon/a/time/";
int count = 0;
int n = 0;

while ((n = source.IndexOf('/', n)) != -1)
{
   n++;
   count++;
}

在我的电脑上,这比5000万次迭代的每个字符解决方案快2秒左右。

2013年修订:

将字符串更改为char[]并遍历该字符串。将5000万次迭代的总时间进一步缩短一到两秒!

char[] testchars = source.ToCharArray();
foreach (char c in testchars)
{
     if (c == '/')
         count++;
}

这个更快:

char[] testchars = source.ToCharArray();
int length = testchars.Length;
for (int n = 0; n < length; n++)
{
    if (testchars[n] == '/')
        count++;
}

为了更好地衡量,从数组的末尾迭代到0似乎是最快的,大约5%。

int length = testchars.Length;
for (int n = length-1; n >= 0; n--)
{
    if (testchars[n] == '/')
        count++;
}

我想知道为什么这可能是谷歌周围(我记得一些关于反向迭代更快),并遇到了这个SO问题,烦人地使用字符串char[]技术。不过,我认为在这种情况下,反转技巧是新的。

在c#中迭代字符串中单个字符的最快方法是什么?

对于字符串分隔符的情况(而不是字符情况,如主题所述): 字符串源= "@@ once@@@upon@@ a@@@time@@@"; Int count = source。Split(new[] {"@@@"}, StringSplitOptions.RemoveEmptyEntries)。长度- 1; 海报的原始源值("/once/upon/a/time/")自然分隔符是一个字符'/',并且响应确实解释了source. split (char[])选项…

我做了一些研究,发现理查德·沃森的解决方案在大多数情况下是最快的。这是文章中每个解决方案的结果表(除了那些使用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;
    }
}