È 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 replaceAll
che 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'
}
}
from
e to
passati per const
riferimento? Cosa fa la tua funzione se from
non c'è? -1
da parte mia per quello.
const
e 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 const
riferimento 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 const
riferimenti. Quindi la funzione non farebbe nemmeno quello per cui era stata scritta.)
Con C ++ 11 puoi usare std::regex
così:
#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_replace
che non accetta la stringa di Qt.
string
con string.toStdString()
.
String
in 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::string
ha un replace
metodo, è 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);
}
}