c++20用std::erase(s, '-')最简洁;旧标准需std::remove_if+erase;避免o(n²)循环删除;utf-8多字节连字符需专门解码。

用 std::erase + std::remove_if 最简洁(C++20)
如果你的编译器支持 C++20,std::erase 是最直接的选择,它内部封装了 remove_if + erase 的惯用法,一行搞定:
std::string s = "a-b-c--d"; std::erase(s, '-');
注意:std::erase 是容器专属函数(重载版本),只对 std::string、std::vector 等生效,不能用于 C 风格字符串或 const char*。
常见错误:误写成 std::erase_if(s, '-') —— 这会编译失败,因为 erase_if 接收的是谓词(predicate),不是要删除的字符值。
兼容 C++11/14/17 的写法:手动组合 remove_if 和 erase
在旧标准下,必须显式调用 std::remove_if 移动元素,再用 string::erase 删除尾部“垃圾”:
std::string s = "a-b-c--d";
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return c == '-'; }), s.end());
关键点:
-
std::remove_if不真正删元素,而是把保留的字符前移,返回新逻辑结尾的迭代器 - 必须配合
erase(..., s.end())才能真正缩短字符串长度 - lambda 里用
c == '-'而不是c == '-'s(后者是 C++14 字符串字面量,不适用于单字符)
避免多次分配:别用 replace 或 find+erase 循环
有人习惯用 while (s.find('-') != std::string::npos) 配合 erase,但这是 O(n²) 时间复杂度,尤其当连字符密集时性能明显下降。
同样,反复调用 replace(如 s.replace(pos, 1, ""))也会触发多次内存重分配。
正确做法始终是单趟扫描 —— remove_if 类方案时间复杂度为 O(n),且只发生一次内存收缩(如果需要)。
处理宽字符或 UTF-8 连字符?先确认字符编码
上述所有方法都按字节(char)操作。如果字符串含 UTF-8 编码的 Unicode 连字符(比如 "‑" U+2011 或 "‒" U+2012),它们占多个字节,c == '-' 判断完全无效。
此时不能简单遍历 char,需用 UTF-8 解码库(如 utf8cpp)或转为 std::u32string 处理。但多数场景下的连字符就是 ASCII '-'(U+002D),无需过度复杂化。
容易被忽略的是:你传入的字符串是否真由纯 ASCII 构成?如果来自用户输入或外部 API,最好加个断言或日志验证前几个字节。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











