【问题标题】:How to find and replace string?如何查找和替换字符串?
【发布时间】:2011-05-04 04:58:12
【问题描述】:

如果sstd::string,那么是否有类似下面的函数?

s.replace("text to replace", "new text");

【问题讨论】:

标签: c++ string


【解决方案1】:

替换第一个匹配项

使用std::string::findstd::string::replace 的组合。

找到第一个匹配项:

std::string s;
std::string toReplace("text to replace");
size_t pos = s.find(toReplace);

替换第一个匹配项:

s.replace(pos, toReplace.length(), "new text");

为您提供方便的简单功能:

void replace_first(
    std::string& s,
    std::string const& toReplace,
    std::string const& replaceWith
) {
    std::size_t pos = s.find(toReplace);
    if (pos == std::string::npos) return;
    s.replace(pos, toReplace.length(), replaceWith);
}

用法:

replace_first(s, "text to replace", "new text");

Demo.


替换所有匹配项

使用std::ostringstream 作为缓冲区定义这个 O(n) 方法:

void replace_all(
    std::string& s,
    std::string const& toReplace,
    std::string const& replaceWith
) {
    std::ostringstream oss;
    std::size_t pos = 0;
    std::size_t prevPos = pos;

    while (true) {
        prevPos = pos;
        pos = s.find(toReplace, pos);
        if (pos == std::string::npos)
            break;
        oss << s.substr(prevPos, pos - prevPos);
        oss << replaceWith;
        pos += toReplace.size();
    }

    oss << s.substr(prevPos);
    s = oss.str();
}

用法:

replace_all(s, "text to replace", "new text");

Demo.


提升

或者,使用boost::algorithm::replace_all:

#include <boost/algorithm/string.hpp>
using boost::replace_all;

用法:

replace_all(s, "text to replace", "new text");

【讨论】:

  • 如果“要替换的文本”长于或短于“新文本”的长度,string::replace 会做什么? memmove 字符串来填补空白?
  • @Alcott 它将为正确大小的“新”string 分配内存,填写数据,并删除“旧”string
  • 只做一个就好了,替换所有的函数有点复杂。
  • 最好有 toReplace 和 replaceWith 的 const 引用。这不是一个功能性问题,但如果您不需要复制此字符串,则更好。 std::string myreplace(std::string &s, const std::string& toReplace, const std::string& replaceWith)
  • 请注意,这只会替换toReplace第一个实例
【解决方案2】:

对于看似如此简单的任务,我们真的需要 Boost 库吗?

要替换所有出现的子字符串,请使用此函数:

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 modified: " 
          << 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

【讨论】:

  • 我说:是的,因为它用经过同行评审的代码替换了您自己的代码。与您使用 std::string 和 std::cout 的原因相同。现在,如果你想减少依赖,那就是另一个问题了。
  • 多次调用 replace() 的问题是,每次它可能会移动字符串的右侧部分(假设“replace”与“find”的长度不同。因此,如果内存不是问题,我宁愿将所有内容都写入一个新字符串。
  • 使用空搜索字符串调用它会导致无限循环。如果 search.empty() 为真,则可能返回主题。 (缺点:这使得您无法搜索空字符串并将其替换为非空字符串)。
【解决方案3】:

是的:replace_all 是提升字符串算法之一:

虽然不是标准库,但在标准库上却有几样东西:

  1. 更自然的符号基于范围而不是迭代器对。这很好,因为您可以嵌套字符串操作(例如,replace_all 嵌套在 trim 中)。标准库函数涉及的更多。
  2. 完整性。 这并不难做到“更好”;标准库相当简陋。例如,boost 字符串算法可让您明确控制字符串操作的执行方式(即,就地或通过副本)。

【讨论】:

  • +1:这个 boost 库似乎鲜为人知,但它可能是我用得最多的一个。
【解决方案4】:
#include <iostream>
#include <string>
using namespace std;

int main ()
{
    string str("one three two four");
    string str2("three");
    str.replace(str.find(str2),str2.length(),"five");
    cout << str << endl;
    return 0;
}

输出

one five two four

【讨论】:

    【解决方案5】:

    就像有人说 boost::replace_all

    这里是一个虚拟的例子:

        #include <boost/algorithm/string/replace.hpp>
    
        std::string path("file.gz");
        boost::replace_all(path, ".gz", ".zip");
    

    【讨论】:

    • 如何对 txt 文件执行此操作?将所有文本放在一个字符串中并替换一些内容。?
    【解决方案6】:

    不完全是这样,但std::string 有许多replace 重载函数。

    通过this link查看每个解释,以及如何使用它们的示例。

    此外,还有多个版本的string::find 函数(如下所列),您可以将它们与string::replace 结合使用。

    • 找到
    • rfind
    • find_first_of
    • find_last_of
    • find_first_not_of
    • find_last_not_of

    另外,请注意&lt;algorithm&gt; 提供了多个版本的replace 函数,您也可以使用它们(而不是string::replace):

    • 替换
    • replace_if
    • replace_copy
    • replace_copy_if

    【讨论】:

    • 这没有回答问题。
    • find 或 rfind 是唯一合适的。 std::replace 仅在字符到字符替换时才适用于字符串,即用下划线或其他内容替换所有空格。
    【解决方案7】:
    // replaced text will be in buffer.
    void Replace(char* buffer, const char* source, const char* oldStr,  const char* newStr)
    {
        if(buffer==NULL || source == NULL || oldStr == NULL || newStr == NULL) return; 
    
        int slen = strlen(source);
        int olen = strlen(oldStr);
        int nlen = strlen(newStr);
    
        if(olen>slen) return;
        int ix=0;
    
        for(int i=0;i<slen;i++)
        {
            if(oldStr[0] == source[i])
            {
                bool found = true;
                for(int j=1;j<olen;j++)
                {
                    if(source[i+j]!=oldStr[j])
                    {
                        found = false;
                        break;
                    }
                }
    
                if(found)
                {
                    for(int j=0;j<nlen;j++)
                        buffer[ix++] = newStr[j];
    
                    i+=(olen-1);
                }
                else
                {
                    buffer[ix++] = source[i];
                }
            }
            else
            {
                buffer[ix++] = source[i];
            }
        }
    }
    

    【讨论】:

    • 不错的功能,但不能很好地处理挤压空格字符。例如,在某些情况下,将两个空格替换为一个空格必须运行多次才能在字符之间只得到一个空格。
    【解决方案8】:

    这是我最终编写的版本,它替换了给定字符串中目标字符串的所有实例。适用于任何字符串类型。

    template <typename T, typename U>
    T &replace (
              T &str, 
        const U &from, 
        const U &to)
    {
        size_t pos;
        size_t offset = 0;
        const size_t increment = to.size();
    
        while ((pos = str.find(from, offset)) != T::npos)
        {
            str.replace(pos, from.size(), to);
            offset = pos + increment;
        }
    
        return str;
    }
    

    例子:

    auto foo = "this is a test"s;
    replace(foo, "is"s, "wis"s);
    cout << foo;
    

    输出:

    thwis wis a test
    

    请注意,即使搜索字符串出现在替换字符串中,也可以正常工作。

    【讨论】:

      【解决方案9】:
      void replace(char *str, char *strFnd, char *strRep)
      {
          for (int i = 0; i < strlen(str); i++)
          {
              int npos = -1, j, k;
              if (str[i] == strFnd[0])
              {
                  for (j = 1, k = i+1; j < strlen(strFnd); j++)
                      if (str[k++] != strFnd[j])
                          break;
                  npos = i;
              }
              if (npos != -1)
                  for (j = 0, k = npos; j < strlen(strRep); j++)
                      str[k++] = strRep[j];
          }
      
      }
      
      int main()
      {
          char pst1[] = "There is a wrong message";
          char pfnd[] = "wrong";
          char prep[] = "right";
      
          cout << "\nintial:" << pst1;
      
          replace(pst1, pfnd, prep);
      
          cout << "\nfinal : " << pst1;
          return 0;
      }
      

      【讨论】:

        【解决方案10】:
        void replaceAll(std::string & data, const std::string &toSearch, const std::string &replaceStr)
        {
            // Get the first occurrence
            size_t pos = data.find(toSearch);
            // Repeat till end is reached
            while( pos != std::string::npos)
            {
                // Replace this occurrence of Sub String
                data.replace(pos, toSearch.size(), replaceStr);
                // Get the next occurrence from the current position
                pos =data.find(toSearch, pos + replaceStr.size());
            }
        }
        

        更多 CPP 实用程序:https://github.com/Heyshubham/CPP-Utitlities/blob/master/src/MEString.cpp#L60

        【讨论】:

          【解决方案11】:

          有没有类似下面的函数?

          另一种(除了使用boost和不同答案中给出的其他方法)可能的方法是使用std::regex_replace,如下所示:

              std::string s{"my name is my name and not my name mysometext myto"}; //this is the original line
              
              std::string replaceThis = "my";
              std::string replaceWith = "your";
              
              std::regex pattern("\\b" + replaceThis + "\\b");
              
              std::string replacedLine = std::regex_replace(s, pattern, replaceWith);
          
              std::cout<<replacedLine<<std::endl;
          

          【讨论】: