如何查找和替换字符串?

69

如果s是一个std::string,那么是否有以下类似的函数?

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

2
http://www.cplusplus.com/reference/string/string/replace/ - Lasse Espeholt
8
没有直接替代方法,但本应该有的。我也寻找同样的方法已经很长时间了。 - iammilind
可能是用另一个字符串替换字符串的一部分的重复问题。 - phuclv
11个回答

102

替换第一个匹配项

使用std::string::find查找字符串toReplace的第一个出现位置。
使用std::string::replace将该位置替换为字符串replaceWith

此函数执行此操作:

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

演示。


替换所有匹配项

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

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

    // Reserves rough estimate of final size of string.
    buf.reserve(s.size());

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

    buf.append(s, prevPos, s.size() - prevPos);
    s.swap(buf);
}

使用方法:

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

演示。


Boost

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

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

使用方法:

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

2
如果“要替换的文本”比“新文本”的长度长或短,string::replace会怎样处理?会使用memmove移动字符串以填充空白吗? - Alcott
只替换一个可能没问题,但是创建一个函数来替换所有的则复杂一些。 - CashCow
最好使用const引用来传递toReplace和replaceWith参数。这不是一个功能性问题,而是一种更好的方式,如果您不需要复制这些字符串。std::string myreplace(std::string &s, const std::string& toReplace, const std::string& replaceWith)。 - T M
这将修改s并返回修改后的副本s - Patrick
1
请注意,这将仅替换“toReplace”的第一个实例 - omni
显示剩余4条评论

34

我们是否真的需要一个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

10
我说:是的,因为它用经过同行评审的代码替换了你自己的代码。这就是你使用 std::string 和 std::cout 的原因。 现在,如果你试图减少依赖关系,那就是另外一个问题了。 - strickli
1
replace() 被多次调用的问题在于每次它可能会移动字符串的右侧部分(假设“replace”与“find”的长度不同)。因此,如果内存不是问题,我更喜欢将所有内容写入新字符串。 - CashCow
1
使用空搜索字符串调用此函数会导致无限循环。也许可以在搜索为空时返回主题。 (缺点:这样做就不能搜索空字符串并将其替换为非空字符串)。 - Matthew Piatt

25

是的:replace_all 是 boost 字符串算法之一:

虽然它不是标准库,但它在一些方面优于标准库:

  1. 更自然的表示法 基于范围而非迭代器对。这很好,因为你可以嵌套字符串操作(例如,一个 trim 中嵌套一个 replace_all)。而对于标准库函数来说,这就比较麻烦。
  2. 完整性。 这并不难做到“更好”;标准库相当简洁。例如,boost 字符串算法让你明确地控制字符串操作是如何执行的(即就地还是通过复制实现)。

1
+1:这个 Boost 库似乎不是很出名,但却是我使用最多的一个。 - Matthieu M.

19
#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

如果找不到字符串,这个可能会崩溃。 - undefined
@yoelhalb 使用固定数据,它永远不会崩溃。这只是一个没有错误检查的示例。 - undefined

7

像一些人说的那样,boost::replace_all

这里有一个虚拟的例子:

    #include <boost/algorithm/string/replace.hpp>

    std::string path("file.gz");
    boost::replace_all(path, ".gz", ".zip");

我该如何对txt文件进行操作?将所有文本放入一个字符串中并替换某些内容。 - borgomeister

3
不完全是这样,但是 std::string 有许多重载函数 replace
请查看此链接以了解每个函数的解释和使用示例。
此外,还有几个版本的 string::find 函数(如下所列),您可以与 string::replace 结合使用。
  • find
  • rfind
  • find_first_of
  • find_last_of
  • find_first_not_of
  • find_last_not_of

另外,请注意,<algorithm> 中还有几个版本的 replace 函数可供使用(而不是使用 string::replace):
  • replace
  • replace_if
  • replace_copy
  • replace_copy_if

2
这并没有回答问题。 - Tom Swirly
find或rfind是唯一适用的函数。如果要进行char-to-char替换,即将所有空格替换为下划线或其他字符,则std :: replace仅适用于字符串。 - CashCow

2
// 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];
        }
    }
}

不错的函数,但是对于挤压空格字符处理得不太好。例如,将两个空格替换为一个空格有时需要运行多次才能在字符之间得到一个空格。 - swdev

0
这是我最终编写的版本,它可以替换给定字符串中目标字符串的所有实例。适用于任何字符串类型。
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

请注意,即使搜索字符串出现在替换字符串中,这个函数仍然可以正确工作。

0
有没有类似以下的函数?
另外一种(除了使用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;

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接