Thay thế chuỗi con bằng một chuỗi con khác C ++


91

Làm cách nào để thay thế một chuỗi con trong một chuỗi bằng một chuỗi con khác trong C ++, tôi có thể sử dụng những hàm nào?

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

5
Khá nhiều bản sao của stackoverflow.com/questions/3418231/… có giải pháp mạnh mẽ hơn trong câu trả lời được chấp nhận.
dave-holm

Câu trả lời:


77

Không có một hàm tích hợp nào trong C ++ để làm điều này. Nếu bạn muốn thay thế tất cả các bản sao của một chuỗi con bằng một chuỗi con khác, bạn có thể làm như vậy bằng cách trộn các lệnh gọi đến string::findstring::replace. Ví dụ:

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

Trong dòng cuối cùng của mã này, tôi đã tăng thêm indexđộ dài của chuỗi được chèn vào chuỗi. Trong ví dụ cụ thể này - thay thế "abc"bằng "def"- điều này thực sự không cần thiết. Tuy nhiên, trong một cài đặt tổng quát hơn, điều quan trọng là phải bỏ qua chuỗi vừa được thay thế. Ví dụ: nếu bạn muốn thay thế "abc"bằng "abcabc", mà không bỏ qua đoạn chuỗi mới được thay thế, mã này sẽ liên tục thay thế các phần của chuỗi mới được thay thế cho đến khi bộ nhớ hết. Một cách độc lập, dù sao cũng có thể nhanh hơn một chút nếu bỏ qua những ký tự mới đó, vì làm như vậy sẽ tiết kiệm được một chút thời gian và công sức của string::findhàm.

Hi vọng điêu nay co ich!


6
Tôi không tin rằng bạn sẽ cần phải tăng chỉ mục bởi vì bạn đã thay thế dữ liệu nên dù sao thì nó cũng sẽ không nhận.
rossb83

1
@Aidiakapi Nếu điều này được chuyển thành một hàm mục đích chung, nó sẽ không bị mắc kẹt trong một vòng lặp vô hạn vì nó nâng vị trí tìm kiếm ( index) qua phần của chuỗi đã được thay thế.
Tim R.

1
@TimR. Bạn nói đúng, tôi đã trả lời rossb83, người nói rằng việc tăng chỉ số là không cần thiết. Chỉ đang cố gắng ngăn chặn thông tin sai lệch. Vì vậy, đối với những người khác: Tăng chỉ số theo độ dài của chuỗi được thay thế (trong trường hợp 3 này) là cần thiết . Không xóa nó khỏi mẫu mã.
Aidiakapi

@FrozenKiwi Tôi rất ngạc nhiên khi biết điều đó. Bạn có chắc là như vậy không?
templatetypedef,

1
@JulianCienfuegos Tôi vừa cập nhật câu trả lời để giải quyết vấn đề này - cảm ơn bạn đã chỉ ra điều đó! (Ngoài ra, Aidiakapi là một người khác ... đó là không chắc chắn ai.)
templatetypedef

68

Thư viện thuật toán chuỗi tăng cường theo cách:

#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
Jay. Tôi cần tăng cường để thay thế tất cả các chuỗi con.
Johannes Overmann

2
Tăng chủ yếu là quá mức cần thiết.
Konrad


43

Tôi nghĩ rằng tất cả các giải pháp sẽ thất bại nếu độ dài của chuỗi thay thế khác với độ dài của chuỗi được thay thế. (tìm kiếm "abc" và thay thế bằng "xxxxxx") Cách tiếp cận chung có thể là:

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

Ở đâu

  • str là chuỗi cơ sở
  • str2 là chuỗi phụ cần tìm
  • str3 là chuỗi con thay thế

3
Điều này chỉ thay thế lần xuất hiện đầu tiên, phải không?
jpo38 10/08/17

4
Tôi sẽ đề nghị đảm bảo kết quả của str.find (str2) không bằng std :: string :: npos auto found = str.find (str2); if (found! = std :: string :: npos) str.replace (found, str2.length (), str3);
Geoff Lentsch

1
Tôi đã không có ý định viết toàn bộ ứng dụng với điều này, nhưng không có bất kỳ kiểm tra vào đầu vào có những trường hợp này được undefined ....
Jeff Zacher

19

Thay thế chuỗi con không khó lắm.

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

Nếu bạn cần hiệu suất, đây là một hàm được tối ưu hóa để sửa đổi chuỗi đầu vào, nó không tạo bản sao của chuỗi:

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

Kiểm tra:

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;

Đầu ra:

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

cần thêm kiểm tra if (search.empty()) { return; }để tránh vòng lặp vô hạn khi vượt qua 'tìm kiếm' trống.
Lập trình viên iOS

Đã thử chức năng ReplaceString - không hoạt động. Nhưng câu trả lời dưới đây: str.replace (str.find (str2), str2.length (), str3); chỉ đơn giản và hoạt động tốt.
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;
}

Vì nó không phải là thành viên của stringlớp, nó không cho phép một cú pháp khá đẹp như trong ví dụ của bạn, nhưng những điều sau sẽ làm tương tự:

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

3

Tổng quát về câu trả lời của rotmax, đây là một giải pháp đầy đủ để tìm kiếm và thay thế tất cả các trường hợp trong một chuỗi. Nếu cả hai chuỗi con có kích thước khác nhau, chuỗi con được thay thế bằng cách sử dụng chuỗi :: xóa và chuỗi :: chèn., Nếu không chuỗi nhanh hơn :: thay thế được sử dụng.

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

Nếu bạn chắc chắn rằng các chuỗi con cần có mặt trong chuỗi, thì điều này sẽ thay thế sự xuất hiện đầu tiên của "abc"để"hij"

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

Nó sẽ bị lỗi nếu bạn không có "abc" trong thử nghiệm, vì vậy hãy sử dụng nó một cách cẩn thận.


1

Đây là một giải pháp tôi đã viết bằng cách sử dụng chiến thuật trình tạo:

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

Kiểm tra:

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

Tôi nghĩ rằng điều này phù hợp với yêu cầu của bạn với ít mã!


Bạn chưa có xem xét nhiều lần xuất hiện / thay thế
Elias Bachaalany

0

phiên bản bị xóa bởi @Czarek Tomczak.
cho phép cả hai std::stringstd::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

Đây là một giải pháp sử dụng đệ quy thay thế tất cả các lần xuất hiện của một chuỗi con bằng một chuỗi con khác. Điều này hoạt động bất kể kích thước của các chuỗi.

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

Ví dụ sử dụng:

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

Giải pháp ngắn gọn mà bạn không cần thêm bất kỳ Thư viện nào.


Có 14 câu trả lời khác cho câu hỏi này. Tại sao không đưa ra lời giải thích tại sao của bạn lại tốt hơn?
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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.