Заменить подстроку другой подстрокой C ++ - PullRequest
74 голосов
/ 10 января 2011

Как я могу заменить подстроку в строке другой подстрокой в ​​C ++, какие функции я могу использовать?

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

Ответы [ 15 ]

64 голосов
/ 10 января 2011

В C ++ нет ни одной встроенной функции для этого. Если вы хотите заменить все экземпляры одной подстроки на другой, вы можете сделать это, смешав вызовы string::find и string::replace. Например:

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

В последней строке этого кода я увеличил index на длину строки, которая была вставлена ​​в строку. В этом конкретном примере - замена "abc" на "def" - на самом деле в этом нет необходимости. Однако в более общем случае важно пропустить только что замененную строку. Например, если вы хотите заменить "abc" на "abcabc", не пропуская вновь замененный сегмент строки, этот код будет непрерывно заменять части вновь замененных строк, пока не будет исчерпана память. Независимо от этого, в любом случае, может быть немного быстрее пропустить этих новых персонажей, поскольку это экономит некоторое время и усилия с помощью функции string::find.

Надеюсь, это поможет!

58 голосов
/ 13 ноября 2012

Библиотека алгоритмов ускорения строк way:

#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"
  );
}
36 голосов
/ 13 марта 2013

Я думаю, что все решения потерпят неудачу, если длина замещающей строки отличается от длины заменяемой строки.(найдите «abc» и замените на «xxxxxx»). Общий подход может быть следующим:

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 );
    }
}
32 голосов
/ 23 декабря 2016

В C ++ 11 вы можете использовать regex_replace:

string test = "abc def abc def";
test = regex_replace(test, regex("def"), "klm");
27 голосов
/ 19 августа 2014
str.replace(str.find(str2),str2.length(),str3);

Где

  • str - базовая строка
  • str2 - подстрока для поиска
  • str3 является замещающей подстрокой
15 голосов
/ 04 февраля 2013

Замена подстрок не должна быть такой сложной.

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

Если вам нужна производительность, вот оптимизированная функция, которая изменяет строку ввода, она не создает копию строки:

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

Тесты:

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;

Вывод:

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
5 голосов
/ 10 января 2011
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;
}

Поскольку он не является членом класса string, он не допускает такой же синтаксис, как в вашем примере, но следующее будет эквивалентно:

test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")
2 голосов
/ 08 января 2014

Обобщая ответ rotmax, мы предлагаем полное решение для поиска и замены всех экземпляров в строке.Если обе подстроки имеют разный размер, подстрока заменяется с помощью string :: erase и string :: insert., В противном случае используется более быстрый 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 );
    }
  }
}
2 голосов
/ 10 января 2011

Если вы уверены, что необходимая подстрока присутствует в строке, то это заменит первое вхождение от "abc" до "hij"

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

Сбой, если у вас нет "abc"в тесте, поэтому используйте его с осторожностью.

1 голос
/ 01 августа 2018

Вот решение, которое я написал, используя тактику строителя:

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

Тесты:

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

}
...