Ist es in C ++ möglich, einen Teil eines Strings durch einen anderen zu ersetzen?
Grundsätzlich möchte ich dies tun:
QString string("hello $name");
string.replace("$name", "Somename");
Ich möchte aber die Standard C ++ - Bibliotheken verwenden.
Ist es in C ++ möglich, einen Teil eines Strings durch einen anderen zu ersetzen?
Grundsätzlich möchte ich dies tun:
QString string("hello $name");
string.replace("$name", "Somename");
Ich möchte aber die Standard C ++ - Bibliotheken verwenden.
Antworten:
Es gibt eine Funktion zum Suchen eines Teilstrings in einem String ( find
) und eine Funktion zum Ersetzen eines bestimmten Bereichs in einem String durch einen anderen String ( replace
), sodass Sie diese kombinieren können, um den gewünschten Effekt zu erzielen:
bool replace(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
std::string string("hello $name");
replace(string, "$name", "Somename");
Als Antwort auf einen Kommentar replaceAll
würde ich wahrscheinlich ungefähr so aussehen:
void replaceAll(std::string& str, const std::string& from, const std::string& to) {
if(from.empty())
return;
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(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
from
und to
pro weitergegeben const
Referenz? Was funktioniert, wenn from
es nicht da ist? -1
von mir dafür.
const
und wenn ich eine solche Dienstprogrammmethode schreiben würde, würde ich sie nur aufrufen, wenn ich das wüsste Ersatz waren gültig
const
ignoriert eines der besten Tools von C ++. Das Übergeben pro const
Referenz sollte der Standardmodus für Funktionsparameter sein. (FTR, ohne das const
könnten Sie nicht einmal String-Literale an Ihre Funktion übergeben, da Sie Temporäre nicht an Nicht- const
Referenzen binden können . Die Funktion würde also nicht einmal das tun, wofür sie geschrieben wurde.)
Mit C ++ 11 können Sie std::regex
wie folgt verwenden:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
Der doppelte Backslash ist erforderlich, um einem Escape-Zeichen zu entkommen.
std::regex_replace
, dass Qts String nicht akzeptiert wird.
string
mit string.toStdString()
.
String
zu std::string
, weil die Frage nicht mit Qt zusammenhängt. Bitte denken Sie darüber nach - ich werde Ihre Antwort danach gerne positiv bewerten.
R"(\$name)"
anstelle von "\\$name"
.
std::string
hat eine replace
Methode, ist es das, wonach Sie suchen?
Du könntest es versuchen:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Ich habe es nicht selbst versucht, lese einfach die Dokumentation auf find()
und replace()
.
Verwenden Sie Folgendes, um die neue Zeichenfolge zurückzugeben:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
Wenn Sie Leistung benötigen, finden Sie hier eine optimierte Funktion, mit der die Eingabezeichenfolge geändert wird. Es wird keine Kopie der Zeichenfolge erstellt:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Ausgabe:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def
Ja, Sie können dies tun, aber Sie müssen die Position der ersten Zeichenfolge mit dem Element find () der Zeichenfolge ermitteln und dann durch das Element replace () ersetzen.
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
Wenn Sie die Standardbibliothek verwenden möchten, sollten Sie sich unbedingt eine Kopie des Buches besorgen The C ++ Standard Library das all diese Dinge sehr gut abdeckt.
Ich benutze im Allgemeinen Folgendes:
std::string& replace(std::string& s, const std::string& from, const std::string& to)
{
if(!from.empty())
for(size_t pos = 0; (pos = s.find(from, pos)) != std::string::npos; pos += to.size())
s.replace(pos, from.size(), to);
return s;
}
Es wird wiederholt aufgerufen std::string::find()
, um andere Vorkommen der gesuchten Zeichenfolge zu lokalisieren, bis std::string::find()
nichts mehr gefunden wird. Da std::string::find()
die Position der Übereinstimmung zurückgegeben wird, besteht kein Problem darin, Iteratoren ungültig zu machen.
Das klingt nach einer Option
string.replace(string.find("%s"), string("%s").size(), "Something");
Sie könnten dies in eine Funktion einschließen, aber diese einzeilige Lösung klingt akzeptabel. Das Problem ist, dass dies nur das erste Vorkommen ändert. Möglicherweise möchten Sie eine Schleife darüber ausführen, aber Sie können auch mehrere Variablen mit demselben Token in diese Zeichenfolge einfügen ( %s
)
str.replace(str.find("%s"), string("%s").size(), "Something");
Wenn alle Zeichenfolgen std :: string sind, treten bei der Verwendung merkwürdige Probleme mit dem Abschneiden von Zeichen auf, sizeof()
da diese für C-Zeichenfolgen und nicht für C ++ - Zeichenfolgen bestimmt sind. Das Update besteht darin, die .size()
Klassenmethode von zu verwenden std::string
.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Das ersetzt sHaystack inline - es ist nicht erforderlich, eine = Zuweisung vorzunehmen.
Anwendungsbeispiel:
std::string sHaystack = "This is %XXX% test.";
std::string sNeedle = "%XXX%";
std::string sReplace = "my special";
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
std::cout << sHaystack << std::endl;
wstring myString = L"Hello $$ this is an example. By $$.";
wstring search = L"$$";
wstring replace = L"Tom";
for (int i = myString.find(search); i >= 0; i = myString.find(search))
myString.replace(i, search.size(), replace);
Wenn Sie es schnell erledigen möchten, können Sie einen Zwei-Scan-Ansatz verwenden. Pseudocode:
Ich bin mir nicht sicher, ob dies zu einem In-Place-Algo optimiert werden kann.
Und ein C ++ 11-Codebeispiel, aber ich suche nur nach einem Zeichen.
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
void ReplaceString(string& subject, char search, const string& replace)
{
size_t initSize = subject.size();
int count = 0;
for (auto c : subject) {
if (c == search) ++count;
}
size_t idx = subject.size()-1 + count * replace.size()-1;
subject.resize(idx + 1, '\0');
string reverseReplace{ replace };
reverse(reverseReplace.begin(), reverseReplace.end());
char *end_ptr = &subject[initSize - 1];
while (end_ptr >= &subject[0])
{
if (*end_ptr == search) {
for (auto c : reverseReplace) {
subject[idx - 1] = c;
--idx;
}
}
else {
subject[idx - 1] = *end_ptr;
--idx;
}
--end_ptr;
}
}
int main()
{
string s{ "Mr John Smith" };
ReplaceString(s, ' ', "%20");
cout << s << "\n";
}
std::string replace(std::string base, const std::string from, const std::string to) {
std::string SecureCopy = base;
for (size_t start_pos = SecureCopy.find(from); start_pos != std::string::npos; start_pos = SecureCopy.find(from,start_pos))
{
SecureCopy.replace(start_pos, from.length(), to);
}
return SecureCopy;
}
Meine eigene Implementierung, bei der berücksichtigt wird, dass die Größe der Zeichenfolge nur einmal geändert werden muss, kann dann ersetzt werden.
template <typename T>
std::basic_string<T> replaceAll(const std::basic_string<T>& s, const T* from, const T* to)
{
auto length = std::char_traits<T>::length;
size_t toLen = length(to), fromLen = length(from), delta = toLen - fromLen;
bool pass = false;
std::string ns = s;
size_t newLen = ns.length();
for (bool estimate : { true, false })
{
size_t pos = 0;
for (; (pos = ns.find(from, pos)) != std::string::npos; pos++)
{
if (estimate)
{
newLen += delta;
pos += fromLen;
}
else
{
ns.replace(pos, fromLen, to);
pos += delta;
}
}
if (estimate)
ns.resize(newLen);
}
return ns;
}
Die Verwendung könnte beispielsweise so sein:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Ich lerne gerade C ++, aber wenn ich einen Teil des zuvor veröffentlichten Codes bearbeite, würde ich wahrscheinlich so etwas verwenden. Dies gibt Ihnen die Flexibilität, eine oder mehrere Instanzen zu ersetzen, und Sie können auch den Startpunkt angeben.
using namespace std;
// returns number of replacements made in string
long strReplace(string& str, const string& from, const string& to, size_t start = 0, long count = -1) {
if (from.empty()) return 0;
size_t startpos = str.find(from, start);
long replaceCount = 0;
while (startpos != string::npos){
str.replace(startpos, from.length(), to);
startpos += to.length();
replaceCount++;
if (count > 0 && replaceCount >= count) break;
startpos = str.find(from, startpos);
}
return replaceCount;
}
Dies könnte noch besser zu bedienen sein
void replace(string& input, const string& from, const string& to)
{
while(true)
{
size_t startPosition = input.find(from);
if(startPosition == string::npos)
break;
input.replace(startPosition, from.length(), to);
}
}