C++20起可用std::erase(s, '~')原地删除所有波浪号;C++11–17需用std::remove_if+erase惯用法;若需保留原串,推荐预分配的手写循环;注意区分ASCII ~与Unicode全角波浪线。

用 std::erase 直接移除所有 ~
C++20 起,std::string 支持范围算法原地擦除,最简方案就是调用 std::erase:
std::string s = "a~b~c~~d"; std::erase(s, '~'); // s 变为 "abcd"
注意:std::erase 是非成员函数,作用于整个容器,不是 s.erase() 成员函数。它内部自动完成查找+擦除,比手写循环更安全、更高效。
常见错误是误用 s.erase(std::find(s.begin(), s.end(), '~')) —— 这只删第一个,且未判 find 返回 end() 导致崩溃。
兼容 C++11–C++17:用 std::remove_if + erase 惯用法
老标准下必须手动组合 std::remove_if 和成员 erase:
立即学习“C++免费学习笔记(深入)”;
std::string s = "x~y~z";
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return c == '~'; }), s.end());
关键点:
-
std::remove_if不真删,只是把匹配元素“挪到末尾”,返回新逻辑尾迭代器 - 必须紧接着用
s.erase(it, s.end())才真正释放内存 - lambda 里用
c == '~',别写成c == "~"(后者是字符串字面量,类型不匹配)
如果要保留原字符串,生成新副本
有时你不希望修改原串,比如参数是 const std::string&:
std::string remove_tildes(const std::string& s) {
std::string result;
result.reserve(s.size()); // 预分配避免多次扩容
for (char c : s) {
if (c != '~') result += c;
}
return result;
}
比起 std::copy_if + back_inserter,手写循环在小字符串上更直观、无额外依赖;reserve 能明显减少内存重分配次数。
别用 result.append(1, c) 或反复 += 不 reserve —— 小字符串影响不大,但大文本(如几 MB 日志)可能慢 2–3 倍。
注意宽字符和编码边界
以上方法只适用于 char 字符串(UTF-8 编码下,~ 是单字节,安全)。如果你处理的是 std::wstring 或 UTF-16/32:
-
std::wstring同样可用std::erase(wstr, L'~') - 但若字符串含 UTF-8 多字节序列,而你按字节删
~,不会破坏其他字符 —— 因为~的 UTF-8 编码就是单字节0x7E,不可能出现在多字节字符中间 - 真正要小心的是误把其他符号(如中文波浪线 ~ U+301C)当成 ASCII
~—— 它们字形相似但码点不同,需单独判断
实际项目里,先确认你要删的是 ASCII 波浪号还是 Unicode 全角波浪线,这点容易被忽略。


















