【问题标题】:Replace substring with another substring C++用另一个子字符串 C++ 替换子字符串
【发布时间】:2011-06-06 07:45:19
【问题描述】:

如何用 C++ 中的另一个子字符串替换字符串中的子字符串,我可以使用哪些函数?

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

【问题讨论】:

标签: c++ string replace substring


【解决方案1】:

C++ 中没有一个内置函数可以做到这一点。如果您想用另一个子字符串替换一个子字符串的所有实例,您可以通过混合调用string::findstring::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 增加了插入字符串的长度。在这个特定的示例中 - 用 "def" 替换 "abc" - 这实际上不是必需的。但是,在更一般的设置中,跳过刚刚被替换的字符串很重要。例如,如果您想用"abcabc" 替换"abc",而不跳过新替换的字符串段,此代码将不断替换部分新替换的字符串,直到内存耗尽。独立地,无论如何跳过这些新字符可能会稍微快一些,因为这样做可以通过 string::find 函数节省一些时间和精力。

希望这会有所帮助!

【讨论】:

  • 我认为您不需要增加索引,因为您已经替换了数据,因此无论如何它都不会拾取它。
  • @Aidiakapi 如果将其转换为通用函数,它不会陷入无限循环,因为它会将搜索位置 (index) 推进到被替换的字符串部分.
  • @TimR。你说得对,我在回复 rossb83,他说索引的增加是不必要的。只是想防止错误信息。所以对于其他所有人:将索引增加替换字符串的长度(在本例中为 3)是必要的。不要从代码示例中删除它。
  • @rossb83 cmets 需要清理或说明。有 5 个赞成的评论说您不必增加索引,然后一个人说您需要以粗体表示。这对来这里学习的人没有帮助。
  • @JulianCienfuegos 我刚刚更新了解决这个问题的答案 - 感谢您指出这一点! (另外,Aidiakapi 是其他人……不确定那是谁。)
【解决方案2】:

如果您确定字符串中存在所需的子字符串,那么这会将第一次出现的"abc" 替换为"hij"

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

如果你在测试中没有“abc”,它会崩溃,所以小心使用它。

【讨论】:

    【解决方案3】:
    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")
    

    【讨论】:

      【解决方案4】:
          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;
          }
      

      我认为这符合您的要求,只需很少的代码!

      【讨论】:

      • 您没有考虑多次出现/替换
      【解决方案5】:

      Boost String Algorithms Library方式:

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

      【讨论】:

      • 杰伊。我需要 boost 来替换所有子字符串。
      • Boost 大多是矫枉过正。
      【解决方案6】:

      替换子字符串应该没有那么难。

      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; } 以避免在传递空“搜索”时出现无限循环。
      • 尝试了 ReplaceString 功能 - 无效。但回答如下: str.replace(str.find(str2),str2.length(),str3);很简单,效果很好。
      【解决方案7】:

      如果替换字符串的长度与要替换的字符串的长度不同,我认为所有解决方案都会失败。 (搜索“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 );
          }
      }
      

      【讨论】:

        【解决方案8】:

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

        【讨论】:

        • 谢谢。使用几年没有问题;然而,最终需要将oldStringnewString 都变成const 参数。
        【解决方案9】:
        str.replace(str.find(str2),str2.length(),str3);
        

        在哪里

        • str 是基本字符串
        • str2 是要查找的子字符串
        • str3 是替换子串

        【讨论】:

        • 这只会替换第一次出现,不是吗?
        • 我建议确保 str.find(str2) 的结果不等于 std::string::npos auto found = str.find(str2); if(found != std::string::npos) str.replace(found, str2.length(), str3);
        • 我不打算用这个来编写整个应用程序,但是在没有对输入进行任何检查的情况下,有些情况是未定义的......
        【解决方案10】:

        @Czarek Tomczak 改进的版本。
        允许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();
            }
        }
        

        【讨论】:

          【解决方案11】:

          ,你可以使用std::regex_replace

          #include <string>
          #include <regex>
          
          std::string test = "abc def abc def";
          test = std::regex_replace(test, std::regex("def"), "klm"); // replace 'def' -> 'klm'
          // test = "abc klm abc klm"
          

          【讨论】:

          • 如果我们有 c++11 那就太好了!!
          • 小心这不能很好地概括,你最终可能会传递一些 std:regex 解释不同的东西,比如 std::regex_replace(test, std::regex("."), "klm") ...
          【解决方案12】:
          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;
          };
          

          【讨论】:

            【解决方案13】:

            这是一个使用递归的解决方案,它用另一个子字符串替换所有出现的子字符串。无论字符串的大小如何,这都有效。

            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;
            

            【讨论】:

              【解决方案14】:

              这是我使用构建器策略编写的解决方案:

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

              【讨论】:

                【解决方案15】:
                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 个其他答案。为什么不解释一下为什么你的更好?
                • 看起来是迄今为止最优雅的答案,没有任何过度设计
                【解决方案16】:
                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;
                }
                

                【讨论】:

                  【解决方案17】:
                  #include <string>
                  

                  第一:

                  void replace_first(std::string& text, const std::string& from,
                     const std::string& to)
                  {
                      const auto at = text.find(from, 0);
                  
                      if (at != std::string::npos)
                          text.replace(at, from.length(), to);
                  }
                  

                  全部:

                  void replace_all(std::string& text, const std::string& from,
                     const std::string& to)
                  {
                      for (auto at = text.find(from, 0); at != std::string::npos;
                          at = text.find(from, at + to.length()))
                      {
                          text.replace(at, from.length(), to);
                      }
                  }
                  

                  计数:

                  size_t replace_count(std::string& text,
                     const std::string& from, const std::string& to)
                  {
                      size_t count = 0;
                  
                      for (auto at = text.find(from, 0); at != std::string::npos;
                          at = text.find(from, at + to.length()))
                      {
                          ++count;
                          text.replace(at, from.length(), to);
                      }
                  
                      return count;
                  }
                  

                  复制:

                  std::string replace_all_copy(const std::string& text,
                     const std::string& from, const std::string& to)
                  {
                      auto copy = text;
                      replace_all(copy, from, to);
                      return copy;
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2011-04-06
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-12-23
                    • 1970-01-01
                    • 2012-12-18
                    • 1970-01-01
                    • 2014-06-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多