C++ 字符串替换

如果我们想把字符串里的某一段内容替换成新的文字,比如把句子中的 "Python" 改成 "C++",在 C++ 中可以使用 std::string 提供的 replace() 成员函数。

在实际开发中,我们既可以直接按已知的下标位置替换,也可以先查找目标位置再执行替换。

按位置替换:replace()

调用 replace() 最基础的方式,是指定起始下标和要替换的字符个数,把原字符串中对应位置的旧字符替换成新字符串。

语法:

str.replace(pos, count, newStr);

说明:

调用 replace() 会直接修改原有的字符串变量 str,它的 3 个参数含义如下:

  • pos(必选):起始下标位置,表示从哪个位置开始替换,下标从 0 开始计算。
  • count(必选):要被替换掉的原字符个数。需要注意,这里是 “字符数量”,而不是结束下标。
  • newStr(必选):用来放入该位置的新字符串内容。

示例 1:替换指定位置的子串

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello, Python!";
    text.replace(7, 6, "C++");

    std::cout << text << '\n';
    return 0;
}

运行结果如下。

Hello, C++!

分析:

在 "Hello, Python!" 中,字母 'P' 位于下标 7,"Python" 一共有 6 个字符。因此 text.replace(7, 6, "C++") 表示从下标 7 开始删掉 6 个旧字符,再把 "C++" 放进去。

这里要注意,replace() 跟 substr() 有一个明显区别:substr() 不会改动原字符串,而是返回一个新字符串。replace() 则会直接修改原字符串本身。

此外,使用 replace(pos, count, newStr) 时,第 2 个参数 count 表示 “要替换掉多少个旧字符”,小伙伴们不要把它当成 “结束下标”。比如想把 "abc123xyz" 中间的 "123" 替换成 "ABC":

std::string text = "abc123xyz";

// 正确方式
text.replace(3, 3, "ABC");

// 错误方式
text.replace(3, 5, "ABC");

在 "abc123xyz" 中,字符 '1' 的下标是 3,"123" 共有 3 个字符,所以第 2 个参数应该传 3,替换后得到 "abcABCxyz"。

如果误把字符 '3' 的下标 5 当作第 2 个参数传进去,程序就会从下标 3 开始连续删掉 5 个字符,把后面的 "xy" 也误删了,结果就会变成 "abcABCz"。

同时,替换操作并不要求新旧字符串的长度一样。新字符串可以比原来更长,也可以比原来更短,替换后原字符串的长度会自动跟着变化。下面我们来看一个例子。

示例 2:替换不同长度的内容

#include <iostream>
#include <string>

int main() {
    std::string text = "I like C";
    std::cout << "替换前长度:" << text.size() << '\n';

    text.replace(7, 1, "Modern C++");
    std::cout << "替换后内容:" << text << '\n';
    std::cout << "替换后长度:" << text.size() << '\n';
    return 0;
}

运行结果如下。

替换前长度:8
替换后内容:I like Modern C++
替换后长度:17

分析:

在这个例子中,原来的 "C" 只有 1 个字符,而换上去的 "Modern C++" 有 10 个字符。执行替换后,通过 size() 函数可以看到,字符串的总长度自动从 8 变成了 17。

结合 find() 查找并替换

前面的例子都是我们已经提前数好了目标在哪个下标位置。但在实际开发中,我们一般不会去人工数下标,而是先调用 find() 函数找到目标字符串的位置,再把找到的下标传给 replace() 完成替换。

示例 3:先查找再替换

#include <iostream>
#include <string>

int main() {
    std::string text = "Learn Python with lvyenet";
    std::string target = "Python";

    std::size_t pos = text.find(target);
    if (pos != std::string::npos) {
        text.replace(pos, target.size(), "C++");
    }

    std::cout << text << '\n';
    return 0;
}

运行结果如下。

Learn C++ with lvyenet

分析:

在上面例子中,text.find(target) 先找出 "Python" 首次出现的起始下标 6 并存入 pos。确认找到后,再调用 text.replace(pos, target.size(), "C++") 把原单词替换成 "C++"。

这种写法比手动写死数字 6 灵活得多。以后就算把要替换的目标词 target 改成其他单词,查找位置和替换长度都会由程序自动计算,我们不需要再去手动修改 replace() 里的参数。

注意 结合 find() 和 replace() 时,必须先判断 pos != std::string::npos。如果没找到目标就直接传入 npos,会触发越界错误导致程序崩溃。

循环替换所有匹配项

如果一段文本里出现了多个相同的目标词,调用一次 find() 配合 replace() 只会替换第一处找到的目标。那如果想要把它们全部替换掉,应该怎么做呢?

其实思路很简单:我们只需要结合 while 循环,反复执行 “查找 → 替换”,并在每次替换后把下一次查找的起始位置往后推进即可。请看下面例子。

示例 4:替换所有匹配项

#include <iostream>
#include <string>

int main() {
    std::string text = "py-go-py";
    std::string target = "py";
    std::string replacement = "cpp";

    std::size_t pos = text.find(target);
    while (pos != std::string::npos) {
        text.replace(pos, target.size(), replacement);
        pos = text.find(target, pos + replacement.size());
    }

    std::cout << text << '\n';
    return 0;
}

运行结果如下。

cpp-go-cpp

分析:

进入循环前,text.find(target) 先找到第 1 个 "py" 的下标 pos 为 0。接着 while 循环的执行过程如下:

  • 第 1 次循环:把下标 0 处的 "py" 换成 "cpp",字符串变为 "cpp-go-py"。接着从下标 0 + 3(即 3)继续往后找,得到第 2 个 "py" 的位置 pos 为 7。
  • 第 2 次循环:把下标 7 处的 "py" 换成 "cpp",字符串变为 "cpp-go-cpp"。接着从下标 7 + 3(即 10)往后找,返回 std::string::npos,循环结束。

这里小伙伴们要特别留意:循环内部每次更新查找起点时,写的是 pos + replacement.size(),也就是直接跳过刚刚替换进去的新词。

为什么要跳过新词的长度呢?假如我们要把句子里的 "C" 替换成 "C++",换上去的新词首字符还是 'C'。如果下次查找不跳过整个 "C++",程序又会在刚换好的新词里找到 'C' 并继续替换,最终陷入死循环。

删除与清空字符

如果我们的目的不是替换成别的词,而是想把字符串里的某一段字符直接删掉,或者清空整个字符串,可以直接调用 std::string 提供的 erase() 和 clear() 函数:

erase(pos, count):从下标 pos 开始直接删除 count 个字符,比如 text.erase(0, 3) 表示删除开头的 3 个字符。如果省略 count,则从下标 pos 一直删除到末尾。

clear():直接把整个字符串里的所有字符全部清空,使其变成空字符串 "",比如 text.clear()。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号