c++oding="utf-8" ?>
c++20 用 std::erase(s, '#') 最简洁安全;兼容旧标准则用 std::remove_if + erase 成对操作;避免 find + erase 循环以防 o(n²) 和漏删。

用 std::erase(C++20)最直接
如果你的编译器支持 C++20,std::erase 是删除字符串中所有指定字符的首选——它原地修改、语义清晰、无迭代器失效风险。
常见错误是手动写循环 + erase,结果因迭代器失效或越界导致未定义行为。而 std::erase 内部已处理好这些细节。
-
std::string s = "a#b#c#d"; std::erase(s, '#');→s变成"abcd" - 只适用于
std::string、std::vector等容器,不支持 C 风格字符串 - 性能上是 O(n),单次遍历完成,比手写
remove_if+erase更易读
兼容 C++11/14/17:用 std::remove_if + erase
这是最广泛兼容的方案,但必须成对使用:std::remove_if 把目标字符“移”到末尾,再用 erase 删掉那段逻辑尾部——单独调用 std::remove_if 不会真正删字符。
容易踩的坑是漏掉第二步,或者传错迭代器范围(比如用了 s.cbegin() 导致编译失败)。
- 正确写法:
auto it = std::remove_if(s.begin(), s.end(), [](char c) { return c == '#'; }); s.erase(it, s.end()); - 如果要删多个掩码字符(如
'#'或'*'),把 lambda 改成return c == '#' || c == '*'; - 注意:
std::remove_if不保证稳定顺序,但对单字符删除无影响;若需保留非目标字符相对顺序(本来就是的),无需额外操作
避免用 find + erase 循环
手动循环调用 std::string::find 和 erase 看似直观,实际有明显缺陷:每次 erase 后剩余字符前移,后续 find 从头开始搜效率低(O(n²)),且容易因索引错位跳过相邻掩码。
例如 "##" 中,第一次删掉第一个 '#' 后,第二个 '#' 移到位置 0,但循环若继续从位置 1 查,就会漏删。
- 除非字符串极短(
- 若坚持用,必须在每次
erase后将查找起点设为pos(而非pos + 1),并检查pos == std::string::npos - 更安全的替代是正则(见下一条),但代价是启动开销和复杂度
需要模式匹配时才用 std::regex_replace
如果“掩码字符”其实是简单通配(如所有空白符 "\s")、或带上下文(如只删行首的 '#'),正则才值得引入;纯删固定单字符,它大材小用,且编译和运行都慢。
典型误用是为删一个 '*' 写 std::regex_replace(s, std::regex("\*"), "")——既慢又增加依赖。
- 仅当掩码逻辑动态变化(如从配置读正则表达式)或需结合上下文(如删“//”后全部内容)时考虑
- 注意:
std::regex在某些标准库实现中(如 libstdc++ 旧版本)性能差或存在 bug,建议先测实际吞吐 - 若真要用,优先用
std::regex_replace返回新字符串,避免对原串反复替换引发多次内存分配
remove_if 和 erase,少一步就白忙活。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











