c++20中可用std::erase原地删除指定字符,语义清晰高效;删子串需find+erase循环;切分场景优先用string_view零拷贝;旧标准可封装erase_all函数。

用 std::erase 直接移除所有指定字符(C++20)
如果目标只是删掉字符串里每一个匹配的字符(比如所有 '-' 或 ','),最简方式是用 C++20 引入的 std::erase:
std::string s = "a-b-c,d"; std::erase(s, '-'); // s 变成 "abc,d" std::erase(s, ','); // s 变成 "abcd"这个操作原地修改、语义清晰,且比手写循环更安全。注意它删除的是「字符」而非子串——传入
'-' 没问题,但传入 "-"(字符串字面量)会编译失败。
要删子串(如 "||")得用 std::string::find + erase 循环
当分隔符是多字符(例如 "::"、
"<br>")时,
std::erase 无能为力。必须手动查找并擦除:
- 用
s.find(delimiter)找到首次出现位置 - 找到后调用
s.erase(pos, delimiter.length()) - 重复查找,但注意:擦除后后续内容前移,下次应从
pos开始找(不是pos + 1),否则可能跳过紧邻的分隔符
示例(删掉所有 "|",虽是单字符但演示逻辑):
<pre class="brush:php;toolbar:false;">std::string s = "a|b||c";
std::string delim = "|";
size_t pos = 0;
while ((pos = s.find(delim, pos)) != std::string::npos) {
s.erase(pos, delim.length());
// 不加 pos++,因为擦除后新内容已落在 pos 处
}漏掉 pos 不递增是常见错误,会导致无限循环或跳过。
想保留分割后的内容?别删,用 std::string_view 切片更高效
如果最终目的是“按分隔符切开再处理”,硬删分隔符反而浪费——尤其字符串很大时,反复 erase 触发多次内存搬移。更合理的做法是用只读切片:
- C++17 起可用
std::string_view配合find/substr拆出各段,零拷贝 - 需要拥有的副本时,再对每个
string_view调用std::string{sv} - 第三方库如
absl::StrSplit或boost::split也默认返回视图或引用,避免冗余复制
删分隔符本身不难,但先想清楚:你真的需要一个“删干净”的新字符串,还是只需要访问被分隔的各段?后者几乎总是更快、更轻量。
兼容旧标准(C++11/14)时,自己封装 erase_all 最稳妥
没有 std::erase 的项目,别反复写循环。直接封装一个可复用的函数:
void erase_all(std::string& s, char c) {
s.erase(std::remove(s.begin(), s.end(), c), s.end());
}
void erase_all(std::string& s, const std::string& substr) {
size_t pos = 0;
while ((pos = s.find(substr, pos)) != std::string::npos) {
s.erase(pos, substr.length());
}
}
注意第一个版本用 std::remove + erase 是经典惯用法(erase-remove idiom),高效且简洁;第二个版本就是上面提到的循环逻辑。别试图用 replace 替换为空字符串——它内部仍要分配和拷贝,不如直接 erase。
真正容易被忽略的点是:分隔符是否可能重叠(如删 "aa" 时,"aaaa" 应变成 "" 还是 "aa"?)。上述循环实现默认非重叠删除;若需重叠(即贪心匹配),得在每次擦除后把 pos 设为 pos + 1,而不是保持原值——这取决于你的业务定义,不是库能替你决定的。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











