Ersetzen Sie den Teilstring durch einen anderen Teilstring C ++

89

Wie kann ich einen Teilstring in einem String durch einen anderen Teilstring in C ++ ersetzen? Welche Funktionen kann ich verwenden?

eg: string test = "abc def abc def";
test.replace("abc", "hij").replace("def", "klm"); //replace occurrence of abc and def with other substring
Steveng
quelle
5
So ziemlich ein Duplikat von stackoverflow.com/questions/3418231/…, das in der akzeptierten Antwort eine robustere Lösung enthält.
Dave-Holm

Antworten:

73

In C ++ ist hierfür keine Funktion integriert. Wenn Sie alle Instanzen eines Teilstrings durch einen anderen ersetzen möchten, können Sie dies tun, indem Sie Aufrufe an string::findund mischen string::replace. Beispielsweise:

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

In der letzten Zeile dieses Codes habe ich indexum die Länge der Zeichenfolge erhöht , die in die Zeichenfolge eingefügt wurde. In diesem speziellen Beispiel - Ersetzen "abc"durch "def"- ist dies eigentlich nicht erforderlich. In einer allgemeineren Einstellung ist es jedoch wichtig, die gerade ersetzte Zeichenfolge zu überspringen. Zum Beispiel, wenn Sie ersetzen möchten "abc"mit "abcabc", ohne das Überspringen neu ersetzt String - Segment, würde dieser Code kontinuierlich Teile der neu ersetzt Strings ersetzen , bis der Speicher erschöpft war. Unabhängig davon kann es ohnehin etwas schneller sein, diese neuen Zeichen zu überspringen, da die string::findFunktion dadurch Zeit und Mühe spart .

Hoffe das hilft!

templatetypedef
quelle
6
Ich glaube nicht, dass Sie den Index erhöhen müssten, da Sie die Daten bereits ersetzt haben, damit sie ohnehin nicht erfasst werden.
Rossb83
1
@Aidiakapi Wenn dies in eine Allzweckfunktion umgewandelt wird, bleibt es nicht in einer Endlosschleife hängen, da die Suchposition ( index) über den Teil der Zeichenfolge hinaus verschoben wird , der ersetzt wurde.
Tim R.
1
@ TimR. Sie haben Recht, ich habe auf rossb83 geantwortet, der angibt, dass die Erhöhung des Index nicht erforderlich ist. Ich habe nur versucht, Fehlinformationen zu verhindern. Also für alle anderen: Es ist notwendig, den Index um die Länge der ersetzten Zeichenfolge (in diesem Fall 3) zu erhöhen . Entfernen Sie es nicht aus dem Codebeispiel.
Aidiakapi
@FrozenKiwi Ich bin überrascht, das zu hören. Sind Sie sicher, dass dies der Fall ist?
Templatetypedef
1
@JulianCienfuegos Ich habe gerade die Antwort aktualisiert, um dies zu beheben - danke, dass Sie darauf hingewiesen haben! (Auch Aidiakapi ist jemand anderes ... nicht sicher, wer das ist.)
Templatetypedef
68

Boost String Algorithms Library Weg:

#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"
  );
}
Oleg Svechkarenko
quelle
4
Jay. Ich brauche Boost, um alle Teilzeichenfolgen zu ersetzen.
Johannes Overmann
2
Boost ist meistens ein Overkill.
Konrad
60

Im können Sie verwenden std::regex_replace:

#include <string>
#include <regex>

std::string test = "abc def abc def";
test = std::regex_replace(test, std::regex("def"), "klm");
Jingguo Yao
quelle
4
Das wäre toll, wenn wir c ++ 11 hätten !!
Michele
1
#include <regex>
Stepan Yakovenko
42

Ich denke, alle Lösungen schlagen fehl, wenn sich die Länge der ersetzenden Zeichenfolge von der Länge der zu ersetzenden Zeichenfolge unterscheidet. (Suche nach "abc" und ersetze durch "xxxxxx") Ein allgemeiner Ansatz könnte sein:

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 );
    }
}
rotmax
quelle
40
str.replace(str.find(str2),str2.length(),str3);

Wo

  • str ist die Basiszeichenfolge
  • str2 ist die zu findende Unterzeichenfolge
  • str3 ist der Ersatz-Teilstring
Jeff Zacher
quelle
3
Dies ersetzt nur das erste Auftreten, nicht wahr?
jpo38
4
Ich würde vorschlagen, sicherzustellen, dass das Ergebnis von str.find (str2) nicht gleich std :: string :: npos ist. Auto found = str.find (str2); if (gefunden! = std :: string :: npos) str.replace (gefunden, str2.length (), str3);
Geoff Lentsch
1
Ich hatte nicht vor, die gesamte Anwendung damit zu schreiben, aber ohne Überprüfung der Eingabe gibt es Fälle, die nicht definiert sind ...
Jeff Zacher
19

Das Ersetzen von Teilzeichenfolgen sollte nicht so schwierig sein.

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 und keine Kopie der Zeichenfolge erstellt wird:

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 changed: " 
          << 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
Zarek Tomczak
quelle
Ich muss eine Prüfung hinzufügen, if (search.empty()) { return; }um eine Endlosschleife zu vermeiden, wenn die leere 'Suche' übergeben wird.
iOS-Programmierer
Versuchte ReplaceString-Funktion - funktioniert nicht. Aber antworte unten: str.replace (str.find (str2), str2.length (), str3); einfach und funktioniert gut.
KAMIKAZE
5
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;
}

Da es kein Mitglied der stringKlasse ist, erlaubt es keine ganz so schöne Syntax wie in Ihrem Beispiel, aber das Folgende wird das Äquivalent tun:

test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
Michael Burr
quelle
2

Verallgemeinernd auf die Antwort von rotmax finden Sie hier eine vollständige Lösung zum Suchen und Ersetzen aller Instanzen in einer Zeichenfolge. Wenn beide Teilzeichenfolgen unterschiedlich groß sind, wird die Teilzeichenfolge mit string :: erase und string :: insert ersetzt. Andernfalls wird die schnellere Zeichenfolge :: replace verwendet.

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

Wenn Sie sicher sind, dass der erforderliche Teilstring in der Zeichenfolge vorhanden ist, ersetzt dies das erste Auftreten von "abc"to"hij"

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

Es wird abstürzen, wenn Sie nicht "abc" im Test haben, also verwenden Sie es mit Vorsicht.

ch0kee
quelle
1

Hier ist eine Lösung, die ich mit der Builder-Taktik geschrieben habe:

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

Tests:

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

}
Den-Jason
quelle
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;
    }

Ich denke, das passt zu Ihrer Anforderung mit wenig Code!

Alessio
quelle
Sie berücksichtigen nicht mehrere Vorkommen / Ersetzungen
Elias Bachaalany
0

die geliebte Version von @Czarek Tomczak.
erlaube beides std::stringund 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();
    }
}
iOS-Programmierer
quelle
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;
};
Krecker
quelle
0

Hier ist eine Lösung mit Rekursion, die alle Vorkommen eines Teilstrings durch einen anderen Teilstring ersetzt. Dies funktioniert unabhängig von der Größe der Zeichenfolgen.

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

Anwendungsbeispiel:

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

Kurze Lösung, bei der Sie keine zusätzlichen Bibliotheken benötigen.

Altinsystems
quelle
Es gibt 14 weitere Antworten auf diese Frage. Warum nicht eine Erklärung anbieten, warum deine besser ist?
chb
0
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;
}
Alex
quelle