C++20 推荐用 std::erase(str, c) 删除指定字符,如 std::erase(s, '[') 和 std::erase(s, ']');C++11–17 需用 erase-remove 惯用法:s.erase(std::remove_if(s.begin(), s.end(), [](char c){return c=='['||c==']';}), s.end());正则替换不推荐用于简单删除。

用 std::erase + std::remove_if 最简洁(C++20)
如果你的编译器支持 C++20,直接用 std::erase 是最安全、最直观的方式,它内部已处理迭代器失效问题,不用手动调用 erase 配合 remove_if。
常见错误是写成 str.erase(std::remove_if(...)) 而漏掉第二个迭代器参数,导致未定义行为;或者在 C++17 及以前误用 std::erase(该函数直到 C++20 才加入标准库)。
-
std::erase(str, '[')删除所有左中括号 -
std::erase(str, ']')删除所有右中括号 - 要一次性删掉两种,得连用两次:先删
'['再删']',顺序无关
示例:
std::string s = "a[b]c[d]e"; std::erase(s, '['); std::erase(s, ']'); // 结果为 "abcde"
兼容 C++11~C++17 的写法:用 erase-remove 惯用法
C++17 及更早版本没有 std::erase,必须显式组合 std::remove_if 和 std::string::erase。关键点在于:不能只调用 remove_if,否则只是“逻辑删除”,字符串长度不变,末尾残留脏数据。
立即学习“C++免费学习笔记(深入)”;
容易踩的坑包括:
- 把
remove_if返回的迭代器传给错误的erase重载(比如误用erase(pos)而非erase(first, last)) - 用
std::remove(只能删固定值)却写成 lambda 判断,结果编译失败 - 对
std::string使用std::remove时传入char字面量,看似可行,但无法同时删两种字符
正确写法(删两种括号):
std::string s = "a[b]c[d]e";
s.erase(std::remove_if(s.begin(), s.end(),
[](char c) { return c == '[' || c == ']'; }),
s.end());
用 std::regex_replace 是否值得?
能用,但不推荐——除非你 already 在项目里重度依赖正则,且字符串里括号嵌套或需上下文判断(比如只删非转义的中括号)。对纯“删所有 [ 和 ]”这种需求,正则开销大、可读性差、还可能因引擎差异引入隐晦 bug(比如某些 stdlib 实现对空匹配处理异常)。
典型误用:
- 写成
std::regex_replace(s, std::regex("\[|\]"), "")—— 看似对,但\[在字符串字面量中实际变成单反斜杠+左括号,regex 解析失败 - 漏掉
std::regex_constants::ECMAScript参数,在某些平台触发未定义行为
真要用,至少写成:
std::regex re(R"([|])"); // 原始字符串避免双重转义 s = std::regex_replace(s, re, "");
性能与边界场景注意点
三种方法在小字符串上差异几乎不可测,但若处理 MB 级文本或高频调用,要注意:
-
std::erase(C++20)和erase-remove都是 O(n),仅遍历一次,内存原地修改 -
regex_replace至少 O(n),实际常数更大,且会额外分配新字符串内存 - 如果字符串含 null 字符(
' '),std::string本身能正常存取,但某些正则库或旧版 CRT 可能提前截断——这时erase-remove最稳妥 - 多线程环境下,确保字符串没被其他线程同时读写;
std::erase不提供线程安全保证
真正容易被忽略的是:中括号在 Windows 路径或 JSON 中常成对出现,但业务逻辑有时需要保留其中内容、只删括号——这时候上面所有方法都过猛,得换用带状态的遍历或更精细的正则。


















