Ersetzen mehrere Zeichen in einem string, der Schnellste Weg?
Bin ich importieren einige Anzahl der Datensätze mit mehreren string
Felder aus einer alten db in eine neue db. Es scheint zu sein, sehr langsam, und ich vermute, es ist, weil ich dies tun:
foreach (var oldObj in oldDB)
{
NewObject newObj = new NewObject();
newObj.Name = oldObj.Name.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š')
.Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć')
.Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ');
newObj.Surname = oldObj.Surname.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š')
.Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć')
.Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ');
newObj.Address = oldObj.Address.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š')
.Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć')
.Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ');
newObj.Note = oldObj.Note.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š')
.Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć')
.Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ');
/*
... some processing ...
*/
}
Nun, ich habe einige Beiträge und Artikel über das Netz, wo ich gesehen habe viele verschiedene Gedanken darüber. Einige sagen, es ist besser, wenn ich das machen würde, regex mit MatchEvaluator
, einige sagen, es ist das beste zu lassen, wie es ist.
Während es ist möglich, dass es wäre leichter für mich einfach ein benchmark-Fall für mich, habe ich beschlossen, eine Frage zu stellen hier den Fall, dass jemand anderes hat, sich zu Fragen die gleiche Frage, oder falls jemand weiß im Voraus.
Also, was ist der Schnellste Weg, dies zu tun in C#?
BEARBEITEN
Habe ich geschrieben die benchmark hier. Auf den ersten Blick sieht es aus wie Richard der Weg mag der Schnellste. Doch sein Weg, noch Marc, der alles tun würde, wegen der falschen Regex-Muster. Nach der Korrektur der Muster von
@"\^@\[\]`\}~\{\\"
zu
@"\^|@|\[|\]|`|\}|~|\{|\\"
scheint es, als ob der alte Weg mit angekettet .Replace () - Aufrufe ist die Schnellste, nachdem alle
Sie Verdacht ist das der Grund? Sollten Sie sich wissen. Sie müssen ein Profil der Anwendung, um die Ordnung der Engpass - nicht erraten.
Ich fragte einmal this und angenommen, dieser, aber ich bin mir nicht sicher, ob das, was Sie suchen.
ob ich Ahnen oder wissen ist nicht hier eine Frage, die Frage ist, wie Sie bringen bessere Leistung, während das ersetzen mehrerer Zeichen in einem string. Es ist nicht relevant, Sie sollten davon ausgehen, dass die
/* ... some processing ... */
Teil der Beispiel-code ist sicherlich nicht der Flaschenhals bedenkt, dass ich die Frage in dieser form. Vielen Dank für den konstruktiven Kommentar obwohl.Mein Punkt ist, dass, wenn Sie don ' T haben die Daten, die Sie möglicherweise tun einige Mikro-Optimierungen, wo es eine chance von makro-Optimierungen. Ahnend, dass ein Stück code, das problem ist, bedeutet nicht, es ist - vielleicht sind Sie konzentrieren Ihre Bemühungen auf die falsch ein problem, das ist alles.
InformationsquelleAutor Dejan Janjušević | 2012-08-10
Du musst angemeldet sein, um einen Kommentar abzugeben.
Vielen Dank für Ihre Eingabe Jungs.
Ich schrieb einen quick-and-dirty-benchmark-test Ihrer Eingaben. Ich habe getestet-parsing-4 strings mit 500.000 Iterationen und 4 Pässe. Das Ergebnis ist wie folgt:
Den code für diesen benchmark ist unten. Bitte überprüfen Sie den code und bestätigen, dass @Richard hat den schnellsten Weg. Beachten Sie, dass ich habe nicht überprüft, ob die Ausgänge korrekt waren, ich nahm an, Sie waren.
Regex
schneller ist. Es ist gebaut, um eine Suche nach Zeichenfolgen mit lächerlichen Wirkungsgrad. Denken Sie immer daran, das Gesetz des Instruments ist schlecht - nutzen Sie die Technologien, die gebaut werden, für das, was Sie zu tun versuchen, so scheuen Sie nicht verwenden Sie die Regex. C# ist nicht alles gut nur weil es eine API dafür. Gute Frage und gute benchmarks @Dejan.Ich würde auch hinzufügen, eine Sache, die zu Ihrem test-strings sind sehr kurz. Dies mag zwar der Fall sein, die Ihre realen Daten (in dem Fall dein Vergleich ist einfach nur fein und spot-on), es verzerrt die Ergebnisse für die längeren Saiten, die mit unterschiedlichen Mengen von Zeichen zu ersetzen usw. Ich vermute, das verantwortlich ist für die relativ gute Leistung der Zeichenfolge.Ersetzen - tut es erstellen Sie die Zeichenfolge immer und immer wieder (allerdings nur, wenn sich etwas ändert), aber sowohl die loop-und string-Ergebnis ist sehr klein, so dass es nicht viel Kosten. Wäre der Unterschied sehr viel stärker ausgeprägt auf lange strings.
Ich denke die Regex-Methode ist die Schnellste, da das Muster fehlt '[' am Anfang des Strings ein ']' am Ende des Strings. Mit dem Beispiel gezeigt, keine Ersetzung wird gemacht, da haben wir keine übereinstimmung! Ich denke, der große Unterschied in der Zeit zwischen den beiden regex-Methoden, kann ganz einfach erklärt.
Ich lief diesen test in 3 Versionen (diff Länge und Ersatzteile) und logicnp war immer am besten, gefolgt von oleksii. Er war am besten noch in der original-test für mich? .NET 4.5, Release, Win7, i7
Um es zusammenzufassen: die ursprünglichen zahlen offenbar nicht die Tatsache widerspiegeln, dass die regexes gebrochen wurden. Ich re-lief der test (hinzufügen meine vorgeschlagene Methode) hinzufügen von Validierung, dass die Ergebnisse richtig waren. Dann nahm ich die Validierung und re-lief Sie. Ich lief auch die MatchEvaluator Methode mit dem gleichen statischen regex, regex erstellt, in der der test ausgeführt werden, und mit Regex.Replace(input,pattern,eval). Die MatchEvaluator Methode war immer die langsamste. Angesichts der test-Daten, angekettet StringBuilder.Ersetzen Sie war immer die Schnellste, dann ToCharArray, string.Kette ersetzen, meine Methode, Marc, dann Richard
InformationsquelleAutor Dejan Janjušević
Nur so ist ein Vergleich der performance selbst. Versuchen Sie, wie in der Q, mit
StringBuilder
und auchRegex.Replace
.Aber micro-benchmarks berücksichtigen nicht den Umfang des ganzen Systems. Wenn diese Methode nur einen kleinen Bruchteil des gesamten system, seine Leistung wahrscheinlich egal, die Allgemeine Anwendungsleistung.
Einige Hinweise:
String
wie oben (nehme ich an) wird wie viele intermediate-Schnüre: mehr Arbeit für die GC. Aber es ist einfach.StringBuilder
ermöglicht die zugrunde liegenden Daten geändert werden, mit jedem ersetzen. Dies schafft weniger Müll. Es ist fast so einfach wie mitString
.regex
ist den meisten komplexen (weil Sie brauchen, um code um die Ersatz -), aber kann in einem einzigen Ausdruck. Ich würde erwarten, dass dies langsamer ist, es sei denn, die Liste der Ersatz ist sehr groß und Ersetzungen sind selten in der input-string (ie. die meisten ersetzen Methodenaufrufe ersetzen nichts, nur kostet die Suche durch die Schnur).Erwarte ich von #2 würde etwas schneller über die wiederholte Verwendung (Tausende Male) aufgrund der geringeren GC laden.
Für die regex-Ansatz müssen Sie etwas wie:
Diese getan werden könnte, in einer wiederverwendbaren Art und Weise durch entsprechende Parametrierung mit einem
Dictionary<char,char>
zu halten, die Ersatz-und wiederverwendbareMatchEvaluator
.oops auf die regex Tippfehler... ich wusste, ich brauchte eine Charakter-Klasse (der Korrektur).
Allerdings, wenn ich Feste die Tippfehler-das Ergebnis war schlechter... sogar langsamer als Marc die statische regex.
Erwähnenswert ist die regex-engine speichert die letzten (15 IIRC) regexes, der an die statischen Methoden, so dass in diesem test würde ich nicht erwarten, zu sehen, einen Unterschied in der ausdrücklich die Erstellung eines Regex-Instanz (nur das erste verwenden der statischen Methode langsamer sein wird für das kompilieren).
InformationsquelleAutor Richard
Versuchen Sie dies:
IndexOfAny wird intern eine Schleife verwenden, die auch. Es gibt keinen Weg, um zu vermeiden, eine einzige Schleife.
Danke für deine Antwort. Bitte werfen Sie einen Blick auf die benchmark ich geschrieben als eine weitere Antwort.
Stimmt, aber IndexOfAny ist unglaublich schnell, wenn es relativ Häufig, dass der string nicht haben, etwas zu ersetzen, könnte es bedeuten erhebliche Einsparungen (einschließlich vollständig zu entfernen, die Erstellung eines neuen char[] - keine großen Kosten, aber immer noch signifikant in den Geltungsbereich der Dinge). Beachten Sie, dass beide
ToCharArray
und die späternew string(charArray)
kopieren Sie die char-Daten der Zeichenkette und den Speicher erforderlich.Die meiste Zeit wird damit verbracht, auf dem Wörterbuch-lookup. Das kann vermieden werden, indem ein char-array mit dem Schlüssel Zeichen als index und die Ersatz-Zeichen als Wert. Dann überprüfen Sie für '\0', um zu sehen, ob es einen Ersatz-char oder nicht.
InformationsquelleAutor logicnp
Eine mögliche Lösung ist die Verwendung eines
StringBuilder
Klasse.Können Sie zuerst überarbeiten Sie den code für eine bestimmte Methode
InformationsquelleAutor oleksii
Könnten Sie lambda Ausdrücke für diese Verwendung von Aggregat-auf eine char anzeigen:
Können Sie führen Sie dieses wie folgt:
InformationsquelleAutor André C. Andersen
Gut, würde ich versuchen etwas wie:
Dieser hat einen einzigen Platz zu erhalten (an der Spitze), und baut eine vorkompilierte
Regex
zu behandeln, die Ersetzungen. Alle Aufwand erfolgt nur ein (daherstatic
).InformationsquelleAutor Marc Gravell
Hybrid StringBuilder-Ansatz mit IndexOfAny:
InformationsquelleAutor user1664043