È possibile in C ++ sostituire parte di una stringa con un'altra stringa?
Fondamentalmente, vorrei fare questo:
QString string("hello $name");
string.replace("$name", "Somename");
Ma vorrei usare le librerie C ++ standard.
È possibile in C ++ sostituire parte di una stringa con un'altra stringa?
Fondamentalmente, vorrei fare questo:
QString string("hello $name");
string.replace("$name", "Somename");
Ma vorrei usare le librerie C ++ standard.
Risposte:
C'è una funzione per trovare una sottostringa all'interno di una stringa ( find) e una funzione per sostituire un intervallo particolare in una stringa con un'altra stringa ( replace), in modo da poterle combinare per ottenere l'effetto desiderato:
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");
In risposta a un commento, penso replaceAllche probabilmente sarebbe simile a questo:
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'
}
}
frome topassati per constriferimento? Cosa fa la tua funzione se fromnon c'è? -1da parte mia per quello.
conste se avessi scritto un metodo di utilità come questo lo chiamerei solo se sapessi il la sostituzione era valida
constè ignorare uno dei migliori strumenti del C ++. Il passaggio per constriferimento dovrebbe essere la modalità predefinita per i parametri della funzione. (FTR, senza il const, non potresti nemmeno passare letterali di stringa alla tua funzione, perché non puoi legare i provvisori ai non constriferimenti. Quindi la funzione non farebbe nemmeno quello per cui era stata scritta.)
Con C ++ 11 puoi usare std::regexcosì:
#include <regex>
...
std::string string("hello $name");
string = std::regex_replace(string, std::regex("\\$name"), "Somename");
La doppia barra rovesciata è necessaria per sfuggire a un personaggio di fuga.
std::regex_replaceche non accetta la stringa di Qt.
stringcon string.toStdString().
Stringin std::string, perché la domanda non è correlata a Qt. Per favore, considera di farlo - Sarò lieto di votare la tua risposta dopo.
R"(\$name)"anziché "\\$name".
std::stringha un replacemetodo, è quello che stai cercando?
Puoi provare:
s.replace(s.find("$name"), sizeof("$name") - 1, "Somename");
Non ho provato me stesso, basta leggere la documentazione su find()e replace().
Per ottenere la nuova stringa restituita, utilizzare questo:
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;
}
Se hai bisogno di prestazioni, ecco una funzione ottimizzata che modifica la stringa di input, non crea una copia della stringa:
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();
}
}
test:
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;
Produzione:
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
Sì, puoi farlo, ma devi trovare la posizione della prima stringa con il membro find () della stringa, e quindi sostituire con il suo membro replace ().
string s("hello $name");
size_type pos = s.find( "$name" );
if ( pos != string::npos ) {
s.replace( pos, 5, "somename" ); // 5 = length( $name )
}
Se stai pensando di utilizzare la Libreria standard, dovresti davvero procurarti una copia del libro The C ++ Standard Library che copre molto bene tutto ciò.
Uso generalmente questo:
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;
}
Chiama ripetutamente std::string::find()per individuare altre occorrenze della stringa cercata fino a quando std::string::find()non trova nulla. Poiché std::string::find()restituisce la posizione della corrispondenza, non abbiamo il problema di invalidare gli iteratori.
Sembra un'opzione
string.replace(string.find("%s"), string("%s").size(), "Something");
Potresti racchiuderlo in una funzione ma questa soluzione a una riga sembra accettabile. Il problema è che questo cambierà solo la prima occorrenza, potresti volerci passare sopra, ma ti permette anche di inserire diverse variabili in questa stringa con lo stesso token ( %s)
str.replace(str.find("%s"), string("%s").size(), "Something");
Se tutte le stringhe sono std :: string, troverai strani problemi con il taglio dei caratteri se usato sizeof()perché è pensato per stringhe C, non per stringhe C ++. La correzione consiste nell'utilizzare il .size()metodo di classe di std::string.
sHaystack.replace(sHaystack.find(sNeedle), sNeedle.size(), sReplace);
Ciò sostituisce sHaystack inline - non è necessario eseguire nuovamente una = assegnazione.
Esempio di utilizzo:
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);
Se si desidera farlo rapidamente, è possibile utilizzare un approccio a due scansioni. Pseudo codice:
Non sono sicuro che questo possa essere ottimizzato per un algoritmo sul posto.
E un esempio di codice C ++ 11 ma cerco solo un carattere.
#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;
}
La mia implementazione, tenendo conto del fatto che la stringa deve essere ridimensionata una sola volta, quindi può avvenire la sostituzione.
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;
}
L'uso potrebbe essere ad esempio così:
std::string dirSuite = replaceAll(replaceAll(relPath.parent_path().u8string(), "\\", "/"), ":", "");
Sto imparando solo ora il C ++, ma modificando parte del codice precedentemente pubblicato, probabilmente userò qualcosa del genere. Ciò ti dà la flessibilità di sostituire 1 o più istanze e ti consente anche di specificare il punto iniziale.
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;
}
Questo potrebbe essere ancora meglio da usare
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);
}
}