Ganti substring dengan substring C ++ lainnya


91

Bagaimana cara mengganti substring dalam string dengan substring lain di C ++, fungsi apa yang dapat saya gunakan?

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

5
Cukup banyak duplikat stackoverflow.com/questions/3418231/… yang memiliki solusi yang lebih kuat dalam jawaban yang diterima.
dave-holm

Jawaban:


77

Tidak ada satu pun fungsi bawaan di C ++ untuk melakukan ini. Jika Anda ingin mengganti semua instance dari satu substring dengan yang lain, Anda dapat melakukannya dengan mencampurkan panggilan ke string::finddan string::replace. Sebagai contoh:

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

Di baris terakhir kode ini, saya telah menambah indexpanjang string yang telah dimasukkan ke dalam string. Dalam contoh khusus ini - mengganti "abc"dengan "def"- ini sebenarnya tidak perlu. Namun, dalam pengaturan yang lebih umum, penting untuk melewati string yang baru saja diganti. Misalnya, jika Anda ingin mengganti "abc"dengan "abcabc", tanpa melewatkan segmen string yang baru diganti, kode ini akan terus-menerus mengganti bagian dari string yang baru diganti hingga memori habis. Secara independen, mungkin akan sedikit lebih cepat untuk melewati karakter baru tersebut, karena melakukan hal itu menghemat waktu dan tenaga oleh string::findfungsinya.

Semoga ini membantu!


6
Saya tidak percaya Anda perlu menaikkan indeks karena Anda telah mengganti data sehingga tidak akan mengambilnya.
rossb83

1
@Aidiakapi Jika ini diubah menjadi fungsi tujuan umum, ini tidak akan macet dalam loop tak terbatas karena memajukan posisi pencarian ( index) melewati bagian dari string yang diganti.
Tim R.

1
@TimR. Anda benar, saya menanggapi rossb83 yang menyatakan bahwa kenaikan indeks tidak perlu. Hanya mencoba untuk mencegah kesalahan informasi. Jadi untuk orang lain: Meningkatkan indeks dengan panjang string yang diganti (dalam hal ini 3) diperlukan . Jangan hapus dari sampel kode.
Aidiakapi

@F frozenKiwi Saya terkejut mendengarnya. Apakah Anda yakin itu masalahnya?
templatetypedef

1
@JulianCienfuegos Saya baru saja memperbarui jawaban untuk menjawab ini - terima kasih telah menunjukkannya! (Juga, Aidiakapi adalah orang lain ... tidak yakin siapa itu.)
templatetypedef

68

Cara Pustaka Algoritme String Tingkatkan :

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

5
Jay. Saya perlu dorongan untuk mengganti semua substring.
Johannes Overmann

2
Boost sebagian besar merupakan pembunuhan besar-besaran.
Konrad


43

Menurut saya semua solusi akan gagal jika panjang string pengganti berbeda dengan panjang string yang akan diganti. (telusuri "abc" dan ganti dengan "xxxxxx") Pendekatan umum mungkin adalah:

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

Dimana

  • str adalah senar dasar
  • str2 adalah sub string untuk ditemukan
  • str3 adalah substring pengganti

3
Ini hanya menggantikan kemunculan pertama, bukan?
jpo38

4
Saya akan menyarankan memastikan hasil str.find (str2) tidak sama dengan std :: string :: npos auto found = str.find (str2); if (ditemukan! = std :: string :: npos) str.replace (ditemukan, str2.length (), str3);
Geoff Lentsch

1
Saya tidak bermaksud untuk menulis seluruh aplikasi dengan ini, tetapi tanpa pemeriksaan pada masukan ada kasus ini yang tidak ditentukan ....
Jeff Zacher

19

Mengganti substring seharusnya tidak terlalu sulit.

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

Jika Anda membutuhkan kinerja, berikut adalah fungsi yang dioptimalkan yang mengubah string input, itu tidak membuat salinan dari string:

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

Tes:

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;

Keluaran:

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

perlu menambahkan centang if (search.empty()) { return; }untuk menghindari loop tak terbatas saat melewati 'pencarian' kosong.
Pemrogram iOS

Mencoba fungsi ReplaceString - tidak bekerja. Tapi jawab di bawah: str.replace (str.find (str2), str2.length (), str3); sederhana dan berfungsi dengan baik.
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;
}

Karena ini bukan anggota stringkelas, ini tidak mengizinkan sintaks sebaik dalam contoh Anda, tetapi yang berikut ini akan melakukan hal yang setara:

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

3

Menggeneralisasi jawaban rotmax, berikut adalah solusi lengkap untuk mencari & mengganti semua contoh dalam sebuah string. Jika kedua substring memiliki ukuran yang berbeda, substring tersebut diganti menggunakan string :: erase dan string :: insert., Jika tidak, string :: replace yang lebih cepat digunakan.

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

Jika Anda yakin bahwa substring yang diperlukan ada dalam string, maka ini akan menggantikan kemunculan pertama "abc"untuk"hij"

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

Ini akan macet jika Anda tidak memiliki "abc" dalam pengujian, jadi gunakan dengan hati-hati.


1

Berikut adalah solusi yang saya tulis menggunakan taktik pembangun:

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

Tes:

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

Saya pikir ini sesuai dengan kebutuhan Anda dengan beberapa kode!


Anda tidak mempertimbangkan beberapa kemunculan / penggantian
Elias Bachaalany

0

versi impoved oleh @Czarek Tomczak.
memungkinkan keduanya std::stringdan 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

Berikut adalah solusi menggunakan rekursi yang menggantikan semua kemunculan substring dengan substring lain. Ini berfungsi tidak peduli ukuran senar.

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

Contoh penggunaan:

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

Solusi singkat di mana Anda tidak memerlukan Perpustakaan tambahan.


1
Ada 14 jawaban lain untuk pertanyaan ini. Mengapa tidak menawarkan penjelasan mengapa milik Anda lebih baik?
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;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.