부분 문자열을 다른 부분 문자열로 바꾸기 C ++


91

C ++에서 문자열의 하위 문자열을 다른 하위 문자열로 어떻게 바꿀 수 있습니까? 어떤 함수를 사용할 수 있습니까?

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

5
stackoverflow.com/questions/3418231/…의 거의 중복 되는 답변으로 더 강력한 솔루션이 있습니다.
dave-holm 2011-06-21

답변:


77

이 작업을 수행하는 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함수의 시간과 노력을 절약하기 때문에 약간 더 빠를 수 있습니다 .

도움이 되었기를 바랍니다!


6
나는 당신이 이미 데이터를 대체했기 때문에 인덱스를 증가시킬 필요가 없다고 믿습니다. 그래서 그것은 어쨌든 그것을 선택하지 않을 것입니다.
rossb83

1
@Aidiakapi 이것이 범용 함수 index로 바뀌면 대체 된 문자열 부분을 지나서 검색 위치 ( )를 앞으로 이동하므로 무한 루프에 갇히지 않습니다 .
Tim R.

1
@TimR. 당신 말이 맞아요, 저는 인덱스 증가가 불필요하다고 말하는 rossb83에 응답했습니다. 잘못된 정보를 막으려는 것뿐입니다. 따라서 다른 모든 사람들에게 : 대체 된 문자열의 길이 (이 경우 3) 만큼 인덱스를 늘릴 필요가 있습니다. 코드 샘플에서 제거하지 마십시오.
Aidiakapi

@FrozenKiwi 나는 그것을 듣고 놀랐습니다. 그게 사실인가요?
templatetypedef

1
@JulianCienfuegos 방금이 문제를 해결하기 위해 답변을 업데이트했습니다. 지적 해 주셔서 감사합니다! (또한 Aidiakapi는 다른 사람입니다 ... 그게 누구인지 확실하지 않습니다.)
templatetypedef

68

부스트 문자열 알고리즘 라이브러리 방식 :

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

4
어치. 모든 하위 문자열을 대체하려면 부스트가 필요합니다.
Johannes Overmann

2
부스트는 대부분 과잉입니다.
Konrad


43

교체 할 문자열의 길이와 교체 할 문자열의 길이가 다르면 모든 솔루션이 실패 할 것이라고 생각합니다. ( "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 );
    }
}

41
str.replace(str.find(str2),str2.length(),str3);

어디

  • str 기본 문자열입니다.
  • str2 찾을 하위 문자열입니다.
  • str3 대체 부분 문자열입니다.

3
이것은 첫 번째 발생만을 대체하지 않습니까?
jpo38

4
str.find (str2)의 결과가 std :: string :: npos auto found = str.find (str2); if (found! = std :: string :: npos) str.replace (found, str2.length (), str3);
Geoff Lentsch 2017

1
나는이와 전체 응용 프로그램을 작성하는 의도는 아니지만 된 정의되지 않은되는이의 경우가 입력 .... 아무 검사없이
제프 ZACHER

19

부분 문자열 교체는 그렇게 어렵지 않습니다.

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

if (search.empty()) { return; }빈 '검색'을 전달할 때 무한 루프를 피하기 위해 추가 확인 이 필요합니다 .
iOS 프로그래머

시도한 ReplaceString 함수-작동하지 않습니다. 그러나 다음과 같이 대답하십시오. str.replace (str.find (str2), str2.length (), str3); 간단하고 잘 작동합니다.
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;
}

string클래스 의 멤버 가 아니기 때문에 예제 에서처럼 멋진 구문을 허용하지 않지만 다음은 동등한 작업을 수행합니다.

test = string_replace( string_replace( test, "abc", "hij"), "def", "klm")

3

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

필요한 부분 문자열이 문자열에 존재한다고 확신하는 경우, 이것은 "abc"to 의 첫 번째 항목을 대체합니다."hij"

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

테스트에 "abc"가 없으면 충돌이 발생하므로주의해서 사용하십시오.


1

다음은 빌더 전술을 사용하여 작성한 솔루션입니다.

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

}

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

나는 이것이 몇 가지 코드로 귀하의 요구 사항에 부합한다고 생각합니다!


당신은 고려 여러 발행 수 / 교체를 고려하지 않습니다
엘리아스 Bachaalany

0

@Czarek Tomczak의 개선 된 버전.
모두 허용 std::string하고 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();
    }
}

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

0

다음은 하위 문자열의 모든 발생을 다른 하위 문자열로 바꾸는 재귀를 사용하는 솔루션입니다. 이것은 문자열의 크기에 관계없이 작동합니다.

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

사용 예 :

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;

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

추가 라이브러리가 필요하지 않은 짧은 솔루션입니다.


이 질문에 대한 다른 답은 14 개 있습니다. 왜 당신의 것이 더 나은지에 대한 설명을 제공하지 않습니까?
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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.