1064 Stimmen

Wie würden Sie das Vorkommen einer Zeichenkette (eigentlich eines Zeichens) innerhalb einer Zeichenkette zählen?

Ich mache gerade etwas, bei dem ich merke, dass ich zählen möchte, wie viele / s, die ich in einer Zeichenkette finden konnte, und dann fiel mir auf, dass es mehrere Möglichkeiten gab, aber ich konnte mich nicht entscheiden, welche die beste (oder einfachste) war.

Im Moment denke ich an so etwas wie:

string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;

Aber es gefällt mir überhaupt nicht, hat jemand Lust?

Ich möchte nicht wirklich etwas ausgraben. RegEx oder doch?

Ich weiß, dass meine Zeichenfolge den gesuchten Begriff enthalten wird, also können Sie davon ausgehen, dass...

Natürlich auch für Streicher wobei Länge > 1 ,

string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;

16voto

Dave Punkte 2667

In C# ist ein netter String-SubString-Zähler dieser unerwartet trickreiche Kerl:

public static int CCount(String haystack, String needle)
{
    return haystack.Split(new[] { needle }, StringSplitOptions.None).Length - 1;
}

15voto

Ben Punkte 141
private int CountWords(string text, string word) {
    int count = (text.Length - text.Replace(word, "").Length) / word.Length;
    return count;
}

Da die ursprüngliche Lösung die schnellste für Zeichen war, nehme ich an, dass sie auch für Zeichenketten funktionieren wird. Hier ist also mein Beitrag.

Für den Kontext: Ich habe in einer Protokolldatei nach Begriffen wie "fehlgeschlagen" und "erfolgreich" gesucht.

Gr, Ben

12voto

preetham Punkte 131
string s = "65 fght 6565 4665 hjk";
int count = 0;
foreach (Match m in Regex.Matches(s, "65"))
  count++;

11voto

bmiller Punkte 1034

Nun, ab .NET 5 (Net core 2.1+ & NetStandard 2.1) haben wir einen neuen König der Iterationsgeschwindigkeit.

"Span<T>" https://docs.microsoft.com/en-us/dotnet/api/system.span-1?view=net-5.0

und String hat ein eingebautes Mitglied, das uns einen Span<Char> zurückgibt

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

Meine Tests zeigen, dass es 62 % schneller ist als ein Straight foreach. Ich habe auch einen Vergleich mit einer for()-Schleife auf einem Span<T>[i] angestellt, ebenso wie mit einigen anderen hier geposteten. Beachten Sie, dass die umgekehrte for()-Iteration auf einem String jetzt langsamer zu sein scheint als ein reines 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%

UPDATE: Dezember 2021, 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%

Ich habe weitere Schleifen hinzugefügt und RegEx eingefügt, damit wir sehen können, was für eine Katastrophe es ist, es in vielen Iterationen zu verwenden. Ich denke, dass der for(++)-Schleifenvergleich in .NET 6 optimiert wurde, um Span intern zu verwenden - da er fast die gleiche Geschwindigkeit wie foreach span hat.

Code Link

7voto

user460847 Punkte 1548
public static int GetNumSubstringOccurrences(string text, string search)
{
    int num = 0;
    int pos = 0;

    if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(search))
    {
        while ((pos = text.IndexOf(search, pos)) > -1)
        {
            num ++;
            pos += search.Length;
        }
    }
    return num;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X