W C ++ nie ma jednej wbudowanej funkcji, która mogłaby to zrobić. Jeśli chcesz zamienić wszystkie wystąpienia jednego podciągu na inny, możesz to zrobić, mieszając wywołania string::findi string::replace. Na przykład:
size_t index = 0;
while (true) {
/* Locate the substring to replace. */
index = str.find("abc", index);
if (index == std::string::npos) break;
/* Make the replacement. */
str.replace(index, 3, "def");
/* Advance index forward so the next iteration doesn't pick it up as well. */
index += 3;
}
W ostatnim wierszu tego kodu zwiększyłem indexo długość ciągu, który został wstawiony do ciągu. W tym konkretnym przykładzie - zastępującego "abc"z "def"- nie jest to rzeczywiście konieczne. Jednak w bardziej ogólnym ustawieniu ważne jest, aby pominąć ciąg, który właśnie został zastąpiony. Na przykład, jeśli chcesz zamienić "abc"z "abcabc", bez pomijania nad nowo wymieniony odcinek ciąg, kod ten będzie stale wymieniać części nowo zastąpionych strun dopóki pamięć została wyczerpana. Niezależnie od tego i tak pomijanie nowych znaków może być nieco szybsze, ponieważ oszczędza to trochę czasu i wysiłku string::findfunkcji.
Nie sądzę, abyś musiał zwiększać indeks, ponieważ już zastąpiłeś dane, aby i tak go nie odebrać.
Rossb83
1
@Aidiakapi Jeśli zostanie to przekształcone w funkcję ogólnego przeznaczenia, nie utknie w nieskończonej pętli, ponieważ przesuwa pozycję wyszukiwania ( index) poza część ciągu, który został zastąpiony.
Tim R.
1
@TimR. Masz rację, odpowiadałem rossb83, który stwierdził, że przyrost indeksu jest niepotrzebny. Próbowałem tylko zapobiec dezinformacji. Więc dla wszystkich innych: Wzrost indeksu o długości zastąpiony ciągiem (w tym przypadku 3) jest to konieczne . Nie usuwaj go z przykładowego kodu.
Aidiakapi
@FrozenKiwi Jestem zaskoczony, że to słyszę. Czy na pewno o to chodzi?
templatetypedef
1
@JulianCienfuegos Właśnie zaktualizowałem odpowiedź, aby rozwiązać ten problem - dzięki za wskazanie tego! (Również Aidiakapi to ktoś inny ... nie jestem pewien, kto to jest.)
Myślę, że wszystkie rozwiązania zawiodą, jeśli długość zastępującego ciągu różni się od długości łańcucha do wymiany. (wyszukaj „abc” i zamień na „xxxxxx”) Ogólne podejście może być następujące:
Sugerowałbym upewnienie się, że wynik str.find (str2) nie jest równy std :: string :: npos auto found = str.find (str2); if (znaleziono! = std :: string :: npos) str.replace (znalezione, str2.length (), str3);
Geoff Lentsch
1
I nie zamierza napisać całą aplikację z tego, ale bez żadnej kontroli na wejściu istnieją przypadki to, że są niezdefiniowane ....
trzeba dodać czek, if (search.empty()) { return; }aby uniknąć nieskończonej pętli, gdy wpisz puste „wyszukiwanie”.
Programista iOS
Wypróbowana funkcja ReplaceString - nie działała. Ale odpowiedz poniżej: str.replace (str.find (str2), str2.length (), str3); po prostu proste i działa dobrze.
KAMIKAZE
5
usingstd::string;
stringstring_replace( string src, stringconst& target, stringconst& repl){
// handle error situations/trivial casesif (target.length() == 0) {
// searching for a match to the empty string will result in // an infinite loop// it might make sense to throw an exception for this casereturn src;
}
if (src.length() == 0) {
return src; // nothing to match against
}
size_t idx = 0;
for (;;) {
idx = src.find( target, idx);
if (idx == string::npos) break;
src.replace( idx, target.length(), repl);
idx += repl.length();
}
return src;
}
Ponieważ nie jest członkiem tej stringklasy, nie pozwala na tak ładną składnię, jak w twoim przykładzie, ale poniższy odpowiednik:
test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
Uogólniając na odpowiedź rotmax, oto pełne rozwiązanie do wyszukiwania i zastępowania wszystkich instancji w ciągu. Jeśli oba podciągi mają różne rozmiary, podciąg jest zamieniany za pomocą string :: erase i string :: insert., W przeciwnym razie używany jest szybszy string :: replace.
voidFindReplace(string& line, string& oldString, string& newString){
constsize_t oldSize = oldString.length();
// do nothing if line is shorter than the string to findif( oldSize > line.length() ) return;
constsize_t newSize = newString.length();
for( size_t pos = 0; ; pos += newSize ) {
// Locate the substring to replace
pos = line.find( oldString, pos );
if( pos == string::npos ) return;
if( oldSize == newSize ) {
// if they're same size, use std::string::replace
line.replace( pos, oldSize, newString );
} else {
// if not same size, replace by erasing and inserting
line.erase( pos, oldSize );
line.insert( pos, newString );
}
}
}
Oto rozwiązanie wykorzystujące rekursję, która zastępuje wszystkie wystąpienia podciągu innym. Działa to niezależnie od rozmiaru strun.
std::stringReplaceString(conststd::string source_string, conststd::string old_substring, conststd::string new_substring){
// Can't replace nothing.if (old_substring.empty())
return source_string;
// Find the first occurrence of the substring we want to replace.size_t substring_position = source_string.find(old_substring);
// If not found, there is nothing to replace.if (substring_position == std::string::npos)
return source_string;
// Return the part of the source string until the first occurance of the old substring + the new replacement substring + the result of the same function on the remainder.return source_string.substr(0,substring_position) + new_substring + ReplaceString(source_string.substr(substring_position + old_substring.length(),source_string.length() - (substring_position + old_substring.length())), old_substring, new_substring);
}
Przykład użycia:
std::string my_cpp_string = "This string is unmodified. You heard me right, it's unmodified.";
std::cout << "The original C++ string is:\n" << my_cpp_string << std::endl;
my_cpp_string = ReplaceString(my_cpp_string, "unmodified", "modified");
std::cout << "The final C++ string is:\n" << my_cpp_string << std::endl;
Odpowiedzi:
W C ++ nie ma jednej wbudowanej funkcji, która mogłaby to zrobić. Jeśli chcesz zamienić wszystkie wystąpienia jednego podciągu na inny, możesz to zrobić, mieszając wywołania
string::find
istring::replace
. Na przykład:size_t index = 0; while (true) { /* Locate the substring to replace. */ index = str.find("abc", index); if (index == std::string::npos) break; /* Make the replacement. */ str.replace(index, 3, "def"); /* Advance index forward so the next iteration doesn't pick it up as well. */ index += 3; }
W ostatnim wierszu tego kodu zwiększyłem
index
o długość ciągu, który został wstawiony do ciągu. W tym konkretnym przykładzie - zastępującego"abc"
z"def"
- nie jest to rzeczywiście konieczne. Jednak w bardziej ogólnym ustawieniu ważne jest, aby pominąć ciąg, który właśnie został zastąpiony. Na przykład, jeśli chcesz zamienić"abc"
z"abcabc"
, bez pomijania nad nowo wymieniony odcinek ciąg, kod ten będzie stale wymieniać części nowo zastąpionych strun dopóki pamięć została wyczerpana. Niezależnie od tego i tak pomijanie nowych znaków może być nieco szybsze, ponieważ oszczędza to trochę czasu i wysiłkustring::find
funkcji.Mam nadzieję że to pomoże!
źródło
index
) poza część ciągu, który został zastąpiony.Sposób biblioteki algorytmów Boost String :
#include <boost/algorithm/string/replace.hpp> { // 1. string test = "abc def abc def"; boost::replace_all(test, "abc", "hij"); boost::replace_all(test, "def", "klm"); } { // 2. string test = boost::replace_all_copy ( boost::replace_all_copy<string>("abc def abc def", "abc", "hij") , "def" , "klm" ); }
źródło
W c ++ 11możesz użyć
std::regex_replace
:#include <string> #include <regex> std::string test = "abc def abc def"; test = std::regex_replace(test, std::regex("def"), "klm");
źródło
Myślę, że wszystkie rozwiązania zawiodą, jeśli długość zastępującego ciągu różni się od długości łańcucha do wymiany. (wyszukaj „abc” i zamień na „xxxxxx”) Ogólne podejście może być następujące:
void replaceAll( string &s, const string &search, const string &replace ) { for( size_t pos = 0; ; pos += replace.length() ) { // Locate the substring to replace pos = s.find( search, pos ); if( pos == string::npos ) break; // Replace by erasing and inserting s.erase( pos, search.length() ); s.insert( pos, replace ); } }
źródło
Gdzie
str
jest ciągiem podstawowymstr2
to podciąg do znalezieniastr3
jest podciągiem zastępczymźródło
Wymiana podciągów nie powinna być taka trudna.
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; }
Jeśli potrzebujesz wydajności, oto zoptymalizowana funkcja, która modyfikuje ciąg wejściowy, ale nie tworzy kopii ciągu:
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(); } }
Testy:
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 changed: " << input << std::endl; ReplaceStringInPlace(input, "bc", "??"); std::cout << "ReplaceStringInPlace() input string modified: " << input << std::endl;
Wynik:
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
źródło
if (search.empty()) { return; }
aby uniknąć nieskończonej pętli, gdy wpisz puste „wyszukiwanie”.using std::string; string string_replace( string src, string const& target, string const& repl) { // handle error situations/trivial cases if (target.length() == 0) { // searching for a match to the empty string will result in // an infinite loop // it might make sense to throw an exception for this case return src; } if (src.length() == 0) { return src; // nothing to match against } size_t idx = 0; for (;;) { idx = src.find( target, idx); if (idx == string::npos) break; src.replace( idx, target.length(), repl); idx += repl.length(); } return src; }
Ponieważ nie jest członkiem tej
string
klasy, nie pozwala na tak ładną składnię, jak w twoim przykładzie, ale poniższy odpowiednik:test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
źródło
Uogólniając na odpowiedź rotmax, oto pełne rozwiązanie do wyszukiwania i zastępowania wszystkich instancji w ciągu. Jeśli oba podciągi mają różne rozmiary, podciąg jest zamieniany za pomocą string :: erase i string :: insert., W przeciwnym razie używany jest szybszy string :: replace.
void FindReplace(string& line, string& oldString, string& newString) { const size_t oldSize = oldString.length(); // do nothing if line is shorter than the string to find if( oldSize > line.length() ) return; const size_t newSize = newString.length(); for( size_t pos = 0; ; pos += newSize ) { // Locate the substring to replace pos = line.find( oldString, pos ); if( pos == string::npos ) return; if( oldSize == newSize ) { // if they're same size, use std::string::replace line.replace( pos, oldSize, newString ); } else { // if not same size, replace by erasing and inserting line.erase( pos, oldSize ); line.insert( pos, newString ); } } }
źródło
Jeśli masz pewność, że wymagany podciąg znajduje się w ciągu, zastąpi to pierwsze wystąpienie
"abc"
to"hij"
test.replace( test.find("abc"), 3, "hij");
Jeśli nie masz w teście „abc”, nastąpi awaria, więc używaj go ostrożnie.
źródło
Oto rozwiązanie, które napisałem przy użyciu taktyki konstruktora:
#include <string> #include <sstream> using std::string; using std::stringstream; string stringReplace (const string& source, const string& toReplace, const string& replaceWith) { size_t pos = 0; size_t cursor = 0; int repLen = toReplace.length(); stringstream builder; do { pos = source.find(toReplace, cursor); if (string::npos != pos) { //copy up to the match, then append the replacement builder << source.substr(cursor, pos - cursor); builder << replaceWith; // skip past the match cursor = pos + repLen; } } while (string::npos != pos); //copy the remainder builder << source.substr(cursor); return (builder.str()); }
Testy:
void addTestResult (const string&& testId, bool pass) { ... } void testStringReplace() { string source = "123456789012345678901234567890"; string toReplace = "567"; string replaceWith = "abcd"; string result = stringReplace (source, toReplace, replaceWith); string expected = "1234abcd8901234abcd8901234abcd890"; bool pass = (0 == result.compare(expected)); addTestResult("567", pass); source = "123456789012345678901234567890"; toReplace = "123"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "-4567890-4567890-4567890"; pass = (0 == result.compare(expected)); addTestResult("start", pass); source = "123456789012345678901234567890"; toReplace = "0"; replaceWith = ""; result = stringReplace(source, toReplace, replaceWith); expected = "123456789123456789123456789"; pass = (0 == result.compare(expected)); addTestResult("end", pass); source = "123123456789012345678901234567890"; toReplace = "123"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "--4567890-4567890-4567890"; pass = (0 == result.compare(expected)); addTestResult("concat", pass); source = "1232323323123456789012345678901234567890"; toReplace = "323"; replaceWith = "-"; result = stringReplace(source, toReplace, replaceWith); expected = "12-23-123456789012345678901234567890"; pass = (0 == result.compare(expected)); addTestResult("interleaved", pass); source = "1232323323123456789012345678901234567890"; toReplace = "==="; replaceWith = "-"; result = utils_stringReplace(source, toReplace, replaceWith); expected = source; pass = (0 == result.compare(expected)); addTestResult("no match", pass); }
źródło
string & replace(string & subj, string old, string neu) { size_t uiui = subj.find(old); if (uiui != string::npos) { subj.erase(uiui, old.size()); subj.insert(uiui, neu); } return subj; }
Myślę, że to pasuje do twoich wymagań z kilkoma kodami!
źródło
ulepszona wersja autorstwa @Czarek Tomczak.
zezwalaj na
std::string
istd::wstring
.template <typename charType> void ReplaceSubstring(std::basic_string<charType>& subject, const std::basic_string<charType>& search, const std::basic_string<charType>& replace) { if (search.empty()) { return; } typename std::basic_string<charType>::size_type pos = 0; while((pos = subject.find(search, pos)) != std::basic_string<charType>::npos) { subject.replace(pos, search.length(), replace); pos += replace.length(); } }
źródło
std::string replace(const std::string & in , const std::string & from , const std::string & to){ if(from.size() == 0 ) return in; std::string out = ""; std::string tmp = ""; for(int i = 0, ii = -1; i < in.size(); ++i) { // change ii if ( ii < 0 && from[0] == in[i] ) { ii = 0; tmp = from[0]; } else if( ii >= 0 && ii < from.size()-1 ) { ii ++ ; tmp = tmp + in[i]; if(from[ii] == in[i]) { } else { out = out + tmp; tmp = ""; ii = -1; } } else { out = out + in[i]; } if( tmp == from ) { out = out + to; tmp = ""; ii = -1; } } return out; };
źródło
Oto rozwiązanie wykorzystujące rekursję, która zastępuje wszystkie wystąpienia podciągu innym. Działa to niezależnie od rozmiaru strun.
std::string ReplaceString(const std::string source_string, const std::string old_substring, const std::string new_substring) { // Can't replace nothing. if (old_substring.empty()) return source_string; // Find the first occurrence of the substring we want to replace. size_t substring_position = source_string.find(old_substring); // If not found, there is nothing to replace. if (substring_position == std::string::npos) return source_string; // Return the part of the source string until the first occurance of the old substring + the new replacement substring + the result of the same function on the remainder. return source_string.substr(0,substring_position) + new_substring + ReplaceString(source_string.substr(substring_position + old_substring.length(),source_string.length() - (substring_position + old_substring.length())), old_substring, new_substring); }
Przykład użycia:
std::string my_cpp_string = "This string is unmodified. You heard me right, it's unmodified."; std::cout << "The original C++ string is:\n" << my_cpp_string << std::endl; my_cpp_string = ReplaceString(my_cpp_string, "unmodified", "modified"); std::cout << "The final C++ string is:\n" << my_cpp_string << std::endl;
źródło
std::string replace(std::string str, std::string substr1, std::string substr2) { for (size_t index = str.find(substr1, 0); index != std::string::npos && substr1.length(); index = str.find(substr1, index + substr2.length() ) ) str.replace(index, substr1.length(), substr2); return str; }
Krótkie rozwiązanie, w którym nie potrzebujesz żadnych dodatkowych bibliotek.
źródło
std::string replace(std::string str, const std::string& sub1, const std::string& sub2) { if (sub1.empty()) return str; std::size_t pos; while ((pos = str.find(sub1)) != std::string::npos) str.replace(pos, sub1.size(), sub2); return str; }
źródło