Was ist der effektive Weg, um alle Vorkommen eines Zeichens durch ein anderes Zeichen in zu ersetzen std::string
?
Wie ersetzt man alle Vorkommen eines Zeichens in einer Zeichenfolge?
groß-z
Kirill V. Ljadwinski
std::string
enthält keine solche Funktion, aber Sie könnten eigenständig verwenden replace
Funktion ab algorithm
Header.
#include <algorithm>
#include <string>
void some_func() {
std::string s = "example string";
std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
-
std::string
ist ein Container speziell für den Betrieb mit Zeichenfolgen entwickelt. Verknüpfung– Kirill W. Ljadwinski
24. Mai 2010 um 11:41 Uhr
-
Leider erlaubt dies, nur ein Zeichen durch ein anderes Zeichen zu ersetzen. Es kann ein Zeichen nicht durch mehr Zeichen (dh durch eine Zeichenfolge) ersetzen. Gibt es eine Möglichkeit, eine Suche durch mehr Zeichen zu ersetzen?
– SasQ
9. August 2012 um 9:26 Uhr
-
@ Kirill V. Lyadvinsky Was ist, wenn ich nur ein Vorkommen entfernen möchte.
– SIFE
22. November 2012 um 14:54 Uhr
-
@KirillV.Lyadvinsky: Wenn ich diese Methode verwende, um alle x durch y zu ersetzen, ist das Ergebnis eine lange y-Zeichenfolge, unabhängig von der ursprünglichen Zeichenfolge. Mich würde mal interessieren, was deiner Meinung nach das Problem sein könnte. (der code ist genau der gleiche wie du geschrieben hast)
– Transzendent
17. Oktober 2013 um 12:08 Uhr
-
@Transcendent: Genau das passiert mit
std::string::replace()
anstattstd::replace()
! ‘x’ (char
) wird implizit gecastetsize_t
[value 120]also wird die ganze Zeichenfolge oder ein Teil davon mit 120 Kopien von ‘y’ aufgefüllt.– IBue
19. Februar 2015 um 18:41 Uhr
Gauthier Boaglio
Im Mittelpunkt steht die Frage character
Ersatz, aber da ich diese Seite sehr nützlich fand (insbesondere Konrads Bemerkung), möchte ich diese allgemeinere Implementierung teilen, die es ermöglicht, damit umzugehen substrings
auch:
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
Verwendungszweck:
std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;
Ausgänge:
Number_Of_Beans
XXjXugtXty
hhhhhhhhhhhhhhhhhhhhhhhhhhhhhck
BEARBEITEN:
Das oben Gesagte kann besser umgesetzt werden, falls Sie Leistungen betreffen, indem Sie nichts zurücksenden (void
) und die Änderungen direkt an der Zeichenfolge vornehmen str
als Argument angegeben, bestanden nach Adresse anstatt nach Wert. Dies würde ein nutzloses und kostspieliges Kopieren der ursprünglichen Zeichenfolge vermeiden, während das Ergebnis zurückgegeben wird. Ihr Anruf, dann…
Code:
static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
// Same inner code...
// No return statement
}
Hoffe, das wird für einige andere hilfreich sein …
-
Dieser hat ein Leistungsproblem in Fällen, in denen die Quellzeichenfolge groß ist und die zu ersetzende Zeichenfolge häufig vorkommt. string::replace() würde viele Male aufgerufen werden, was viele String-Kopien verursacht. Siehe meine Lösung, die dieses Problem behebt.
– Ingmar
21. April 2015 um 6:44 Uhr
-
Nit-Picking voraus: nach Adresse => per Referenz. Ob es sich um eine Adresse handelt oder nicht, ist ein Implementierungsdetail.
– Max Truxa
18. Mai 2015 um 16:16 Uhr
-
Sollte man eigentlich prüfen, ob
from
string ist leer, sonst kommt es zu einer Endlosschleife.– Neuling
5. September 2015 um 2:23 Uhr
Onkel Zeiv
Ich dachte, ich würde in die werfen Boost-Lösung auch:
#include <boost/algorithm/string/replace.hpp>
// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "@");
// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "@");
-
Dann fehlen dir ein paar
-I
Flags für Ihren Compiler, damit er die Boost-Bibliotheken auf Ihrem System findet. Vielleicht müssen Sie es sogar zuerst installieren.– Martin Ueding
17. Mai 2019 um 9:56 Uhr
-
Das obige ist effektiver, da es mit std lib herauskommt. Nicht alle verwenden die Boost-Bibliothek 😉
– hfrmobil
20. März 2020 um 10:49 Uhr
Ingmar
Stellen Sie sich einen großen binären Blob vor, in dem alle 0x00-Bytes durch “\1\x30” und alle 0x01-Bytes durch “\1\x31” ersetzt werden sollen, da das Transportprotokoll keine \0-Bytes zulässt.
In Fällen, in denen:
- der ersetzende und der zu ersetzende String haben unterschiedliche Längen,
- Es gibt viele Vorkommen der zu ersetzenden Zeichenfolge innerhalb der Quellzeichenfolge und
- die Quellzeichenfolge ist groß,
die bereitgestellten Lösungen können nicht angewendet werden (weil sie nur einzelne Zeichen ersetzen) oder haben ein Performance-Problem, weil sie string::replace mehrmals aufrufen würden, was immer wieder Kopien der Größe des Blobs erzeugt. (Ich kenne die Boost-Lösung nicht, vielleicht ist es aus dieser Perspektive in Ordnung)
Dieser geht alle Vorkommen im Quellstring ab und baut den neuen String Stück für Stück auf Einmal:
void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
std::string newString;
newString.reserve(source.length()); // avoids a few memory allocations
std::string::size_type lastPos = 0;
std::string::size_type findPos;
while(std::string::npos != (findPos = source.find(from, lastPos)))
{
newString.append(source, lastPos, findPos - lastPos);
newString += to;
lastPos = findPos + from.length();
}
// Care for the rest after last occurrence
newString += source.substr(lastPos);
source.swap(newString);
}
Ein einfaches Suchen und Ersetzen für ein einzelnes Zeichen würde etwa so aussehen:
s.replace(s.find("x"), 1, "y")
Um dies für die gesamte Saite zu tun, wäre es am einfachsten, bis zu Ihrer zu loopen s.find
beginnt zurückzukehren npos
. Ich nehme an, Sie könnten auch fangen range_error
um die Schleife zu verlassen, aber das ist irgendwie hässlich.
-
Dies ist zwar wahrscheinlich eine geeignete Lösung, wenn die Anzahl der zu ersetzenden Zeichen im Vergleich zur Länge der Zeichenfolge klein ist, aber es lässt sich nicht gut skalieren. Wenn der Anteil der zu ersetzenden Zeichen in der ursprünglichen Zeichenfolge zunimmt, nähert sich diese Methode zeitlich O(N^2).
– und und
24. Mai 2010 um 14:37 Uhr
-
Wahr. Meine allgemeine Philosophie ist es, das Einfache (zu schreiben und zu lesen) zu tun, bis die Ineffizienzen echte Probleme verursachen. Es gibt einige Umstände, in denen Sie möglicherweise riesige Saiten haben, bei denen O (N ** 2) wichtig ist, aber in 99% der Fälle sind meine Saiten 1K oder weniger.
– TED
25. Mai 2010 um 3:40 Uhr
-
… davon abgesehen gefällt mir Kirills Methode besser (und hatte sie bereits positiv bewertet).
– TED
25. Mai 2010 um 3:41 Uhr
-
Was passiert, wenn “x” nicht gefunden wird? Und warum verwendest du doppelte Klammern?
– Prasath Govind
25. August 2015 um 11:26 Uhr
-
@PrasathGovind – Ich habe nur die erforderlichen Anrufe angezeigt (daher “so etwas wie”). Wichtige, aber verwirrende Details wie die richtige Fehlerbehandlung wurden dem Leser als Übung überlassen. Was “doppelte Klammern” betrifft, bin ich mir nicht sicher, was das ist oder wovon Sie sprechen. Für mich ist das eine “Klammer”.
{
Charakter. Ich weiß nicht, was eine “Doppelklammer” ist. Vielleicht haben Sie ein Problem mit der Schriftart?– TED
25. August 2015 um 12:54 Uhr
Volomike
Wenn Sie mehr als ein einzelnes Zeichen ersetzen möchten und nur damit zu tun haben std::string
, dann würde dieses Snippet funktionieren und sNeedle in sHaystack durch sReplace ersetzen, und sNeedle und sReplace müssen nicht dieselbe Größe haben. Diese Routine verwendet die While-Schleife, um alle Vorkommen zu ersetzen, und nicht nur das erste, das von links nach rechts gefunden wird.
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
-
Dies ist zwar wahrscheinlich eine geeignete Lösung, wenn die Anzahl der zu ersetzenden Zeichen im Vergleich zur Länge der Zeichenfolge klein ist, aber es lässt sich nicht gut skalieren. Wenn der Anteil der zu ersetzenden Zeichen in der ursprünglichen Zeichenfolge zunimmt, nähert sich diese Methode zeitlich O(N^2).
– und und
24. Mai 2010 um 14:37 Uhr
-
Wahr. Meine allgemeine Philosophie ist es, das Einfache (zu schreiben und zu lesen) zu tun, bis die Ineffizienzen echte Probleme verursachen. Es gibt einige Umstände, in denen Sie möglicherweise riesige Saiten haben, bei denen O (N ** 2) wichtig ist, aber in 99% der Fälle sind meine Saiten 1K oder weniger.
– TED
25. Mai 2010 um 3:40 Uhr
-
… davon abgesehen gefällt mir Kirills Methode besser (und hatte sie bereits positiv bewertet).
– TED
25. Mai 2010 um 3:41 Uhr
-
Was passiert, wenn “x” nicht gefunden wird? Und warum verwendest du doppelte Klammern?
– Prasath Govind
25. August 2015 um 11:26 Uhr
-
@PrasathGovind – Ich habe nur die erforderlichen Anrufe angezeigt (daher “so etwas wie”). Wichtige, aber verwirrende Details wie die richtige Fehlerbehandlung wurden dem Leser als Übung überlassen. Was “doppelte Klammern” betrifft, bin ich mir nicht sicher, was das ist oder wovon Sie sprechen. Für mich ist das eine “Klammer”.
{
Charakter. Ich weiß nicht, was eine “Doppelklammer” ist. Vielleicht haben Sie ein Problem mit der Schriftart?– TED
25. August 2015 um 12:54 Uhr
Adrià Arrufat
Der Vollständigkeit halber, hier ist, wie man es mit macht std::regex
.
#include <regex>
#include <string>
int main()
{
const std::string s = "example string";
const std::string r = std::regex_replace(s, std::regex("x"), "y");
}
Es scheint, dass stdlib scheiße ist, wenn es um solche “erweiterten” Funktionen geht. Verwenden Sie besser QString oder eine allgemeine Bibliothek, wenn Sie anfangen, fehlende Dinge zu finden.
– Kiruahxh
17. März 2021 um 16:14 Uhr