Alt dizeyi başka bir alt dize C ++ ile değiştirin


91

Bir dizedeki bir alt dizeyi C ++ 'da başka bir alt dizeyle nasıl değiştirebilirim, hangi işlevleri kullanabilirim?

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

5
Kabul edilen yanıtta daha sağlam bir çözüme sahip olan stackoverflow.com/questions/3418231/… adresinin hemen hemen bir kopyası .
dave-holm

Yanıtlar:


77

Bunu yapmak için C ++ 'da yerleşik bir işlev yoktur. Bir alt dizenin tüm örneklerini başka bir alt dizeyle değiştirmek isterseniz, bunu string::findve çağrılarını karıştırarak yapabilirsiniz string::replace. Örneğin:

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

Bu kodun son satırında index, dizeye eklenen dizenin uzunluğunu artırdım. Değiştirilmesi - Bu özel örnekte "abc"ile "def"- bu aslında gerekli değildir. Bununla birlikte, daha genel bir ortamda, yeni değiştirilen dizeyi atlamak önemlidir. Değiştirmek istediğiniz Örneğin, "abc"ile "abcabc"yeni değiştirilen dize segmenti göz ardı etmeden, hafıza bitkin kadar, bu kod sürekli yeni değiştirilen dizeleri parçaları yerini alacak. Bağımsız olarak, bu yeni karakterleri atlamak biraz daha hızlı olabilir, çünkü bunu yapmak string::findişlev tarafından biraz zaman ve çaba tasarrufu sağlar.

Bu yardımcı olur umarım!


6
İndeksi artırmanız gerekeceğine inanmıyorum çünkü zaten almasın diye verileri zaten değiştirdiniz.
rossb83

1
@Aidiakapi Eğer bu genel amaçlı bir işleve dönüştürülürse, arama konumunu ( index) değiştirilen dizgenin parçasını geçerek ilerlettiği için sonsuz döngüde sıkışıp kalmaz .
Tim R.

1
@TimR. Haklısın, endeks artışının gereksiz olduğunu söyleyen rossb83'e yanıt veriyordum. Yanlış bilgileri önlemeye çalışıyordu. Bu nedenle, diğer herkes için: Dizini, değiştirilen dizenin uzunluğu kadar artırmak (bu durumda 3) gereklidir . Kod örneğinden çıkarmayın.
Aidiakapi

@FrozenKiwi Bunu duyduğuma şaşırdım. Durumun bu olduğundan emin misin?
templatetypedef

1
@JulianCienfuegos Bu konuyu ele almak için cevabı güncelledim - bunu belirttiğiniz için teşekkürler! (Ayrıca, Aidiakapi başka biri ... onun kim olduğundan emin değilim.)
templatetypedef

68

Dize Algoritmaları Kitaplığı yolunu artırın :

#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. Tüm alt dizeleri değiştirmek için desteğe ihtiyacım var.
Johannes Overmann

2
Güçlendirme çoğunlukla aşırı bir beceridir.
Konrad


43

Değiştirilen dizinin uzunluğu değiştirilecek dizinin uzunluğundan farklıysa tüm çözümlerin başarısız olacağını düşünüyorum. ("abc" yi arayın ve "xxxxxx" ile değiştirin) Genel bir yaklaşım şunlar olabilir:

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

Nerede

  • str temel dizedir
  • str2 bulunacak alt dizedir
  • str3 yedek alt dizedir

3
Bu sadece ilk oluşun yerini alıyor, değil mi?
jpo38

4
Str.find (str2) sonucunun std :: string :: npos auto found = str.find (str2) 'ye eşit olmadığından emin olmayı öneririm; eğer (bulundu! = std :: string :: npos) str.replace (bulunan, str2.length (), str3);
Geoff Lentsch

1
Tüm başvuruyu bununla yazmak niyetinde değildim, ancak girdide herhangi bir kontrol olmadan bununla ilgili tanımlanmamış durumlar var ....
Jeff Zacher

19

Alt dizeleri değiştirmek o kadar zor olmamalıdır.

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

Performansa ihtiyacınız varsa, işte giriş dizesini değiştiren optimize edilmiş bir işlev, dizenin bir kopyasını oluşturmaz:

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

Testler:

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;

Çıktı:

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; }boş 'arama' geçtiğinde sonsuz döngüden kaçınmak için kontrol eklemeniz gerekir .
iOS programcısı

ReplaceString işlevi denendi - çalışmadı. Ancak aşağıdaki yanıt: str.replace (str.find (str2), str2.length (), str3); sadece basit ve iyi çalışıyor.
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;
}

stringSınıfın bir üyesi olmadığı için , örneğinizdeki kadar güzel bir sözdizimine izin vermez, ancak aşağıdakiler eşdeğerini yapacaktır:

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

3

Rotmax'ın cevabını genelleştiren işte bir dizedeki tüm örnekleri aramak ve değiştirmek için tam bir çözüm. Her iki alt dizge de farklı boyuttaysa, alt dizge string :: erase ve string :: insert. Kullanılarak değiştirilir, aksi takdirde daha hızlı string :: replace kullanılır.

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

Dizede gerekli alt dizenin bulunduğundan eminseniz, bu, dizenin ilk geçtiği yerin yerini alacaktır "abc"."hij"

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

Testte "abc" yoksa çökecektir, bu yüzden dikkatli kullanın.


1

İşte inşaatçı taktiğini kullanarak yazdığım bir çözüm:

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

Testler:

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

Bunun birkaç kodla ihtiyacınıza uyduğunu düşünüyorum!


Birden fazla
oluşum

0

@Czarek Tomczak tarafından geliştirilen versiyon.
ikisine de izin ver std::stringve 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

Burada, bir alt dizenin tüm oluşumlarını başka bir alt dizeyle değiştiren özyineleme kullanan bir çözüm. Bu, dizelerin boyutu ne olursa olsun çalışır.

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

Kullanım örneği:

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

Fazladan Kitaplığa ihtiyaç duymadığınız kısa çözüm.


1
Bu sorunun başka 14 cevabı var. Neden sizinkinin daha iyi olduğuna dair bir açıklama sunmuyorsunuz?
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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.