最常用方式是先用std::string::find定位子串起始位置,再用erase删除;必须检查find返回值是否为npos,否则触发未定义行为;erase第二参数是长度而非结束下标。

用 std::string::find + std::string::erase 删除第一个匹配子串
最常用也最直接的方式:先定位子串起始位置,再擦除。注意 find 返回 std::string::npos 表示没找到,必须检查,否则传给 erase 会触发未定义行为。
常见错误是忽略返回值判断,或误把 npos 当作 0 处理:
std::string s = "hello world hello";
size_t pos = s.find("hello");
if (pos != std::string::npos) {
s.erase(pos, 5); // 第二个参数是长度,不是结束位置
}
// 结果:s == " world hello"
-
erase(pos, len)的len是要删的字符数,不是下标范围 - 如果子串为空(
""),find总返回 0,小心无限循环 - 删除后原字符串内存可能不重分配,但迭代器/指针失效
批量删除所有出现的子串(循环 + erase)
想删光所有匹配项,不能用固定 for 循环遍历索引——因为每次 erase 后后续字符前移,索引会错乱。正确做法是边找边删,且每次从新位置继续搜。
典型写法:
std::string s = "ababababa";
std::string to_remove = "aba";
size_t pos = 0;
while ((pos = s.find(to_remove, pos)) != std::string::npos) {
s.erase(pos, to_remove.length());
// 不加 pos += to_remove.length() —— 因为删掉后新内容已前移,下次从同一 pos 继续找
}
// 结果:s == "bba"
- 第二次
find必须传入当前pos,否则会重复匹配开头 - 若子串可重叠(如删
"aa"于"aaaa"),这种写法只删不重叠的;要删重叠的需手动控制pos++ - 频繁
erase可能导致多次内存移动,大数据量时性能较差
用 std::regex_replace 替换为空字符串(适合复杂模式)
当子串有通配、边界或需要大小写不敏感时,正则更灵活。但开销明显高于纯字符串操作,别为简单字面量滥用。
基础用法:
#include <regex> std::string s = "Price: $12.99, Discount: $3.50"; s = std::regex_replace(s, std::regex(R"(\$\d+\.\d+)"), ""); // 结果:s == "Price: , Discount: "</regex>
-
std::regex构造可能抛std::regex_error,生产环境建议预编译或捕获异常 - 默认不支持全局替换?错——
regex_replace默认就是全匹配替换,不用额外标志 - Windows 下 MSVC 对某些正则语法支持较弱(如 lookahead),跨平台慎用
避免内存拷贝的就地删除(C++20 std::erase / std::erase_if)
C++20 引入了容器级擦除算法,对 std::string 也适用,语义清晰且内部优化更好。但它删的是满足条件的单个字符,不是子串——所以不能直接替代 find+erase。
但可以组合使用:比如先用 find 定位,再用 std::erase 按范围删(本质还是调 erase);或者用于删除所有特定字符:
std::string s = "a1b2c3";
std::erase(s, '1'); // 删所有 '1' → "ab2c3"
std::erase_if(s, [](char c) { return std::isdigit(c); }); // 删所有数字 → "abc"
-
std::erase和std::erase_if是基于迭代器的,不依赖find,但也不处理子串逻辑 - 它们在 C++20 才标准化,旧项目需确认编译器支持(GCC 10+/Clang 10+/MSVC 2019 16.8+)
- 真正“零拷贝”的子串删除不存在——
string是连续内存,删中间必然要移动后面内容
find+erase 就够了;唯一容易被忽略的是:**删完后原字符串的 c_str() 指针可能失效,且 data() 地址不一定变,但内容已变——千万别缓存旧指针复用**。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











