Ich mache etwas, bei dem mir klar wurde, dass ich zählen wollte, wie viele /
s ich in einer Zeichenfolge finden konnte, und dann fiel mir auf, dass es mehrere Möglichkeiten gab, aber ich konnte mich nicht entscheiden, was das Beste (oder Einfachste) war .
Im Moment gehe ich mit so etwas wie:
string source = "/once/upon/a/time/";
int count = source.Length - source.Replace("/", "").Length;
Aber ich mag es überhaupt nicht, irgendwelche Abnehmer?
Ich möchte nicht wirklich danach graben RegEx
, oder?
Ich weiß, dass meine Zeichenfolge den Begriff haben wird, nach dem ich suche, also können Sie davon ausgehen, dass ...
Natürlich für Saiten mit einer Länge> 1 ,
string haystack = "/once/upon/a/time";
string needle = "/";
int needleCount = ( haystack.Length - haystack.Replace(needle,"").Length ) / needle.Length;
LEN(ColumnToCheck) - LEN(REPLACE(ColumnToCheck,"N",""))
.Antworten:
Wenn Sie .NET 3.5 verwenden, können Sie dies in einem Einzeiler mit LINQ tun:
Wenn Sie LINQ nicht verwenden möchten, können Sie dies tun mit:
Sie werden überrascht sein zu erfahren, dass Ihre ursprüngliche Technik etwa 30% schneller zu sein scheint als beide! Ich habe gerade einen schnellen Benchmark mit "/ einmal / nach / a / Zeit /" durchgeführt und die Ergebnisse sind wie folgt:
(Die Zeiten sind für 50.000.000 Iterationen, sodass Sie in der realen Welt wahrscheinlich keinen großen Unterschied bemerken werden.)
quelle
f == '\'
handelt von Zeichen in einer Zeichenfolge, nicht von Zeichenfolgen in einer ZeichenfolgeMuss schneller sein als das
source.Replace()
alleine.quelle
quelle
RegexOptions.IgnoreCase
.Regex.Escape(...)
so wollennew System.Text.RegularExpressions.Regex(needle).Matches(haystack).Count;
Wenn Sie nach ganzen Zeichenfolgen und nicht nur nach Zeichen suchen möchten:
Lesen Sie als "Nehmen Sie für jedes Zeichen in der Zeichenfolge den Rest der Zeichenfolge, beginnend mit diesem Zeichen, als Teilzeichenfolge; zählen Sie ihn, wenn er mit der Zielzeichenfolge beginnt."
quelle
Ich habe einige Nachforschungen angestellt und festgestellt, dass die Lösung von Richard Watson in den meisten Fällen am schnellsten ist. Das ist die Tabelle mit den Ergebnissen aller Lösungen im Beitrag (mit Ausnahme derjenigen, die Regex verwenden, da beim Parsen von Zeichenfolgen wie "test {test" Ausnahmen ausgelöst werden).
Sie können sehen, dass beim Ermitteln der Anzahl der Vorkommen von kurzen Teilzeichenfolgen (1-5 Zeichen) in kurzen Zeichenfolgen (10-50 Zeichen) der ursprüngliche Algorithmus bevorzugt wird.
Außerdem sollten Sie für Teilzeichenfolgen mit mehreren Zeichen den folgenden Code verwenden (basierend auf der Lösung von Richard Watson ).
quelle
Regex.Escape(needle)
source="aaa" substring="aa"
bin ich es nur, aber ich habe erwartet, dass ich 2 zurück bekomme, nicht 1. Um dies zu "beheben", wechseln Sien += substring.Length
zun++
overlapped
Flagge hinzufügen , um Ihren Fall wieoverlapped=True;.... if(overlapped) {++n;} else {n += substring.Length;}
LINQ funktioniert in allen Sammlungen, und da Zeichenfolgen nur eine Sammlung von Zeichen sind, wie wäre es mit diesem netten kleinen Einzeiler:
Stellen Sie sicher, dass Sie
using System.Linq;
oben in Ihrer Codedatei.Count
eine Erweiterungsmethode aus diesem Namespace haben.quelle
int
Buchstaben befinden sich alle in Home-Schlüsseln,var
nicht jedoch. Warten Sie, ich benutze DvorakAuf meinem Computer ist es für 50 Millionen Iterationen etwa 2 Sekunden schneller als die Lösung für jedes Zeichen.
Revision 2013:
Ändern Sie die Zeichenfolge in ein Zeichen [] und durchlaufen Sie diese. Reduziert die Gesamtzeit für 50-Meter-Iterationen um ein oder zwei Sekunden!
Das geht noch schneller:
Aus gutem Grund scheint die Iteration vom Ende des Arrays bis 0 mit etwa 5% am schnellsten zu sein.
Ich habe mich gefragt, warum das so sein könnte und habe gegoogelt (ich erinnere mich an etwas über das schnellere Umkehren von Iterationen) und bin auf diese SO-Frage gestoßen, bei der die Zeichenfolge bereits ärgerlich verwendet wird, um die Technik zu char []. Ich denke jedoch, dass der Umkehrtrick in diesem Zusammenhang neu ist.
Was ist der schnellste Weg, um einzelne Zeichen in einer Zeichenfolge in C # zu durchlaufen?
quelle
source.IndexOf('/', n + 1)
dien++
und die Klammern der Zeit setzen und verlieren :) Setzen Sie auch eine Variablestring word = "/"
anstelle des Zeichens.quelle
Diese beiden funktionieren nur für Suchbegriffe mit einem Zeichen ...
kann sich für längere Nadeln als besser herausstellen ...
Aber es muss einen eleganteren Weg geben. :) :)
quelle
Bearbeiten:
quelle
source.Split(new[]{"//"}, StringSplitOptions.None).Count - 1
für Trennzeichen mit mehreren Zeichen.In C # ist ein netter String SubString-Zähler dieser unerwartet knifflige Kerl:
quelle
quelle
stringToMatch
entgehen die Bedürfnisse, nicht dieinput
.Da die ursprüngliche Lösung für Zeichen die schnellste war, wird sie vermutlich auch für Zeichenfolgen gelten. Also hier ist mein Beitrag.
Für den Kontext: Ich habe in einer Protokolldatei nach Wörtern wie "fehlgeschlagen" und "erfolgreich" gesucht.
Gr, Ben
quelle
quelle
Für alle, die eine gebrauchsfertige String-Erweiterungsmethode wünschen,
Folgendes verwende ich, das auf den besten Antworten basiert:
quelle
quelle
Ich denke, der einfachste Weg, dies zu tun, ist die Verwendung der regulären Ausdrücke. Auf diese Weise können Sie dieselbe Aufteilungsanzahl erhalten wie mit myVar.Split ('x'), jedoch in einer Einstellung mit mehreren Zeichen.
quelle
Dies zählt jedes Mal, wenn das Programm "/ s" genau findet (Groß- und Kleinschreibung beachten), und die Anzahl der Vorkommen davon wird in der Variablen "Vorkommen" gespeichert.
quelle
Ich hatte das Gefühl, dass uns bestimmte Arten der Teilzeichenfolgenzählung fehlten, wie unsichere Byte-für-Byte-Vergleiche. Ich habe die Methode des Originalplakats und alle Methoden zusammengestellt, die mir einfallen.
Dies sind die String-Erweiterungen, die ich gemacht habe.
Gefolgt vom Testcode ...
Ergebnisse: CSX entspricht CountSubstrX und CCX entspricht CountCharX. "chr" durchsucht eine Zeichenfolge nach "_" und "durchsucht eine Zeichenfolge nach" und ", und" mlw "durchsucht eine Zeichenfolge nach" muchlongerword ".
Und schließlich hatte ich eine Datei mit 3,6 Millionen Zeichen. Es wurde "derp adfderdserp dfaerpderp deasderp" 100.000 Mal wiederholt. Ich habe mit den oben genannten Methoden 100 Mal nach "derp" in der Datei gesucht.
Meine 4. Methode ist definitiv der Gewinner, aber realistisch gesehen ist all dies vernachlässigbar, wenn eine Datei mit 3,6 Millionen Zeichen 100 Mal nur 1586 ms als der schlimmste Fall benötigte.
Übrigens habe ich auch in der 3,6-Millionen-Zeichen-Datei mit den 100-fachen CountSubstr- und CountChar-Methoden nach dem Zeichen 'd' gesucht. Ergebnisse...
Die ursprüngliche Postermethode ist dementsprechend für Nadeln mit einem einzelnen Charakter in einem großen Heuhaufen sehr schlecht.
Hinweis: Alle Werte wurden auf die Ausgabe der Release-Version aktualisiert. Ich habe versehentlich vergessen, auf dem Release-Modus aufzubauen, als ich dies zum ersten Mal gepostet habe. Einige meiner Aussagen wurden geändert.
quelle
Eine generische Funktion für das Auftreten von Zeichenfolgen:
quelle
Eine Variation von Richard Watsons Antwort, die mit zunehmender Effizienz etwas schneller ist, je öfter das Zeichen in der Zeichenfolge vorkommt, und weniger Code!
Obwohl ich sagen muss, ohne jedes Szenario ausführlich zu testen, habe ich eine sehr signifikante Geschwindigkeitsverbesserung festgestellt, indem ich Folgendes verwendet habe:
quelle
Musste etwas Ähnliches tun, um bedingte Anweisungen aus einer Zeichenfolge zu testen.
Ersetzte das, wonach ich suchte, durch ein einzelnes Zeichen und zählte die Instanzen des einzelnen Zeichens.
Offensichtlich muss das einzelne Zeichen, das Sie verwenden, überprüft werden, damit es nicht in der Zeichenfolge vorhanden ist, bevor dies geschieht, um falsche Zählungen zu vermeiden.
quelle
String in String:
Finden Sie "etc" in ".. JD JD JD JD usw. und usw. JDJDJDJDJDJDJDJD und usw."
Überprüfen Sie die Leistung, bevor Sie diese als unsolide / ungeschickt verwerfen ...
quelle
Meine erste Einstellung gab mir so etwas wie:
Die Nadel im Heuhaufen mit Ersetzen und Teilen ergibt mehr als 21 Sekunden, während dies etwa 15,2 Sekunden dauert.
Bearbeiten Sie nach dem Hinzufügen eines Bits, das
substring.Length - 1
dem charIndex hinzugefügt werden würde (wie es sollte), bei 11,6 Sekunden.Bearbeiten 2: Ich habe eine Zeichenfolge mit 26 zweistelligen Zeichenfolgen verwendet. Hier sind die Zeiten, die auf dieselben Beispieltexte aktualisiert wurden:
Nadel im Heuhaufen (OP-Version): 7,8 Sekunden
Vorgeschlagener Mechanismus: 4,6 Sekunden.
Bearbeiten 3: Beim Hinzufügen des Einzelzeicheneckens wurden 1,2 Sekunden benötigt.
Edit 4: Für den Kontext: 50 Millionen Iterationen wurden verwendet.
quelle
Ich dachte, ich würde meine Erweiterungsmethode in den Ring werfen (siehe Kommentare für weitere Informationen). Ich habe kein formelles Benchmarking durchgeführt, aber ich denke, dass es für die meisten Szenarien sehr schnell sein muss.
EDIT: OK - diese SO-Frage hat mich dazu gebracht, mich zu fragen, wie sich die Leistung unserer aktuellen Implementierung gegenüber einigen der hier vorgestellten Lösungen verhalten würde. Ich entschied mich für ein kleines Benchmarking und stellte fest, dass unsere Lösung sehr gut mit der Leistung der von Richard Watson bereitgestellten Lösung übereinstimmt , bis Sie eine aggressive Suche mit großen Zeichenfolgen (100 Kb +) und großen Teilzeichenfolgen (32 Kb +) durchführen ) und viele eingebettete Wiederholungen (10K +). Zu diesem Zeitpunkt war unsere Lösung etwa 2X bis 4X langsamer. Angesichts dessen und der Tatsache, dass uns die von Richard Watson vorgestellte Lösung wirklich gefällt, haben wir unsere Lösung entsprechend überarbeitet. Ich wollte dies nur für alle verfügbar machen, die davon profitieren könnten.
Unsere ursprüngliche Lösung:
Und hier ist unsere überarbeitete Lösung:
quelle
quelle
Es wird nur jedes Zeichen in der Zeichenfolge überprüft. Wenn das Zeichen das gesuchte Zeichen ist, fügen Sie eines zum Zählen hinzu.
quelle
Wenn Sie diese Webseite besuchen , werden 15 verschiedene Methoden verglichen, einschließlich der Verwendung paralleler Schleifen.
Der schnellste Weg scheint darin zu bestehen, entweder eine einzelne for-Schleife mit Thread (wenn Sie die .Net-Version <4.0 haben) oder eine parallele for-Schleife (wenn Sie .Net> 4.0 mit Tausenden von Überprüfungen verwenden) zu verwenden.
Angenommen, "ss" ist Ihre Suchzeichenfolge, "ch" ist Ihr Zeichenarray (wenn Sie mehr als ein Zeichen haben, das Sie suchen), dann ist hier der grundlegende Kern des Codes, der die schnellste Laufzeit mit einem Thread hatte:
Der Benchmark-Quellcode wird ebenfalls bereitgestellt, damit Sie Ihre eigenen Tests durchführen können.
quelle
Dies dient zum Zählen der Zeichenvorkommen. In diesem Beispiel lautet die Ausgabe "a4b4j3".
quelle
Für den Fall eines Zeichenfolgenbegrenzers (nicht für den Zeichenfall, wie im Betreff angegeben):
string source = "@@@ einmal @@@ nach @@@ a @@@ Zeit @@@";
int count = source.Split (new [] {"@@@"}, StringSplitOptions.RemoveEmptyEntries) .Length - 1;
Der natürliche Begrenzer des ursprünglichen Quellwerts des Posters ("/ einmal / nach / a / Zeit /") ist ein Zeichen '/', und die Antworten erklären die Option source.Split (char []).
quelle
using System.Linq;
int CountOf => "A :: BC :: D" .Split ("::"). Länge - 1;
quelle