2011-01-10 8 views
51

Jak mogę zamienić podciąg w łańcuchu na inny podciąg w C++, z jakich funkcji mogę skorzystać?Zamień podciąg na inny podciąg C++

eg: string test = "abc def abc def"; 
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring 
+3

Prawie duplikat http://stackoverflow.com/questions/3418231/c-replace-part- z-a-string-with-another-string, który ma bardziej niezawodne rozwiązanie w zaakceptowanej odpowiedzi. –

Odpowiedz

49

Nie ma jednej wbudowanej funkcji w C++, aby to zrobić. Jeśli chcesz zamienić wszystkie wystąpienia jednego podciągu na inny, możesz to zrobić, łącząc połączenia z numerami string::find i 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, mam zwiększany index przez długość łańcucha, który został wprowadzony do łańcucha. W tym konkretnym przykładzie - zastąpienie "abc" przez "def" - nie jest to 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 zastąpić "abc" wartością, bez przeskakiwania nowo wyciąganego segmentu łańcucha, ten kod będzie w sposób ciągły zastępował części nowo zamienionych ciągów, aż do wyczerpania pamięci. Niezależnie od tego może być nieco szybsze pomijanie nowych znaków, ponieważ oszczędza to trochę czasu i wysiłku dzięki funkcji string::find.

Mam nadzieję, że to pomoże!

+5

Nie sądzę, że konieczne jest zwiększenie indeksu, ponieważ dane zostały już zastąpione, więc i tak go nie podniosą. – rossb83

+0

@Aidiakapi Jeśli funkcja ta zostanie przekształcona w funkcję ogólnego przeznaczenia, nie utknie w nieskończonej pętli, ponieważ przesuwa pozycję wyszukiwania ('index') o część zastępowanego ciągu znaków. –

+1

@TimR. Masz rację, odpowiadałem na rossb83, który stwierdził, że przyrost indeksu jest niepotrzebny. Próbowałem tylko zapobiec dezinformacji. Tak więc dla wszystkich pozostałych: ** Zwiększenie indeksu o długość zastępowanego ciągu ** (w tym przypadku 3) ** jest konieczne **. Nie usuwaj go z próbki kodu. – Aidiakapi

2

Jeżeli jesteś pewien, że wymagana podciąg jest obecna w łańcuchu, to zastąpi pierwszego wystąpienia "abc" do "hij"

test.replace(test.find("abc"), 3, "hij"); 

Będzie on upaść, jeśli nie masz „abc” w teście, tak używaj go ostrożnie.

6
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 klasy string, nie pozwala już tak piękny składni jak w przykładzie, ale dodaje zrobi równoważne:

test = string_replace(string_replace(test, "abc", "hij"), "def", "klm") 
0
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 pasuje to do twoich wymagań za pomocą kilku kodów!

+0

Nie bierzesz pod uwagę wielu wystąpień/zastępstw –

49

Boost String Algorithms Library sposób:

#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" 
); 
} 
12

Wymiana podciągi nie powinno być takie trudne.

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, tutaj jest zoptymalizowana funkcja, która modyfikuje ciąg wejściowy, to nie tworzy kopię napisu:

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; 

Output :

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 
+0

trzeba dodać sprawdź 'if (search.empty()) {return; } ', aby uniknąć nieskończonej pętli po przejściu pustego 'wyszukiwania'. –

+0

Wypróbowana funkcja ReplaceString - nie działa. Ale odpowiedź poniżej: str.replace (str.find (str2), str2.length(), str3); po prostu proste i działa dobrze. – KAMIKAZE

31

Myślę, że wszystkie rozwiązania zawiodą, jeśli długość zastępującego łańcucha różni się od długości łańcucha, który ma zostać zastąpiony.(Szukaj „abc” i zastąpić przez „xxxxxx”) Ogólne podejście może być:

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); 
    } 
} 
2

uogólniając na odpowiedź rotmax, oto jest pełne rozwiązanie do wyszukiwania & zastąpić wszystkie wystąpienia w ciąg. Jeśli oba podłańcuchy mają różny rozmiar, podłańcuch jest zastępowany za pomocą ciągu :: erase i string :: insert. W przeciwnym razie używany jest szybszy ciąg :: 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); 
    } 
    } 
} 
13
str.replace(str.find(str2),str2.length(),str3); 

Gdzie

  • str jest ciąg baza
  • str2 jest podsłowo znaleźć
  • str3 jest podciąg wymiana
+0

To jest najprostsza i najfajniejsza odpowiedź. – KAMIKAZE

+0

tak proste i naprawdę działa !!! :) – Nick

+2

To tylko zastępuje pierwszy występ, prawda? – jpo38

0

impoved version @Czarek Tomczak.
zezwala zarówno na std::string i std::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(); 
    } 
} 
19

W C++ 11, można użyć regex_replace:

string test = "abc def abc def"; 
test = regex_replace(test, regex("def"), "klm"); 
+2

Byłoby świetnie, gdybyśmy mieli C++ 11 !! – Michele

0
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; 
};