C++20可用std::erase(s, '$')原地删除所有$;C++11–17需用s.erase(std::remove(s.begin(), s.end(), '$'), s.end());若仅删开头连续$,应使用find_first_not_of配合erase。

用 std::erase 直接移除所有 '$' 字符(C++20)
如果你的编译器支持 C++20,最简洁安全的做法就是用 std::erase ——它原地修改、不越界、不手动管理迭代器:
std::string s = "$$hello$world$"; std::erase(s, '$'); // s 变成 "helloworld"
注意:std::erase 是容器算法,只适用于 std::string(本质是 std::basic_string),不能用于 C 风格字符串或 const char*。它会遍历整个字符串,把每个匹配字符“挤掉”,时间复杂度 O(n),但底层做了优化,比手写循环更可靠。
兼容 C++11/14/17:用 erase–remove 惯用法
老标准下没有 std::erase,必须手动组合 std::remove 和 erase。这是标准做法,不是权宜之计:
std::string s = "$$hello$world$"; s.erase(std::remove(s.begin(), s.end(), '$'), s.end());
常见错误包括:
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 只调用
std::remove不跟erase→ 字符串长度不变,末尾残留脏数据 - 传入
s.cbegin()/s.cend()→ 编译失败,remove要求可写迭代器 - 误用
std::remove_if写冗余 lambda:[c] { return c == '$'; }→ 完全没必要,直接用值即可
只删前缀(即开头连续的 $),不是所有 $
标题说“前缀”,但实际需求常有歧义。如果真只要去掉**开头的连续美元符**(比如把 "$$$abc$def" 变成 "abc$def"),就不能用上面两种方法:
std::string s = "$$$abc$def";
auto pos = s.find_first_not_of('$');
if (pos != std::string::npos) {
s.erase(0, pos);
} else {
s.clear(); // 全是 $ 的情况
}
关键点:
-
find_first_not_of返回第一个非'$'的位置,比手写 while 循环更清晰 - 必须检查
npos,否则erase(0, npos)会清空整个字符串(这是定义行为,但容易误以为是 bug) - 这个逻辑和“删所有
$”完全不等价,别混用
性能与边界场景提醒
三种方式在小字符串上差别不大,但要注意:
- 空字符串、全是
$的字符串、含嵌入 null('\0')的字符串 ——std::string本身支持 null,以上方法都正常工作,无需额外处理 - 如果字符串非常长(MB 级),且只需删前缀,
find_first_not_of是 O(k)(k 是前缀长度),比遍历全部快得多 - 不要用
replace或正则(std::regex_replace)——启动开销大、易出错、编译慢,纯属杀鸡用牛刀
真正容易被忽略的是语义:前缀 ≠ 所有,所有 ≠ 前缀。看日志、配置项或协议文档时,先确认清楚要处理的是哪一种。

















