C++20用std::erase(s, '"')和std::erase(s, '\'')最简洁安全;C++11起可用s.erase(remove_if(...), s.end());手动遍历erase易出错不推荐。

用 std::erase 删除所有单引号和双引号(C++20)
如果你的编译器支持 C++20,std::erase 是最简洁安全的方式,它直接修改原字符串并自动处理迭代器失效问题。
-
std::erase是<string>中的非成员函数,作用于容器而非迭代器范围,避免手写循环出错 - 对
std::string调用时,会就地删除所有匹配字符,返回删除个数(可忽略) - 注意:不能用于 C 风格字符串(
char*),只适用于std::string
std::string s = "He said \"Hello\" and 'bye'!"; std::erase(s, '\"'); // 删除所有双引号 std::erase(s, '\''); // 删除所有单引号
用 std::remove_if + erase(C++11 及以上)
这是兼容性最广的方案,适用于所有支持 C++11 的环境,但必须配对使用 std::remove_if 和 erase,漏掉后者会导致“逻辑删除”残留。
-
std::remove_if不真正删除元素,而是把保留的元素前移,返回新逻辑结尾迭代器 - 必须紧接着调用
string.erase(),否则字符串长度不变,只是末尾内容未定义 - 判断条件可用 lambda,同时检查两种引号:
["](c) { return c == '\'' || c == '"'; }
std::string s = "It's \"quoted\" and 'nested'";
s.erase(std::remove_if(s.begin(), s.end(),
[](char c) { return c == '\'' || c == '\"'; }),
s.end());
手动遍历 + erase(不推荐,但需理解为何危险)
新手常写的 for 循环逐个 erase 容易崩溃或跳过字符,根本原因是 erase 会使后续迭代器失效,且字符串长度动态变化。
- 正向遍历时删一个,后面所有字符前移,下标 i 若自增就会跳过新移到 i 位置的字符
- 反向遍历(
i--)可避免跳过,但仍要小心边界(i >= 0对无符号类型无效) - 除非调试或教学目的,否则不要用此方式——性能差、易出错、可读性低
// 错误示例(会跳过相邻引号):
for (size_t i = 0; i < s.length(); ++i) {
if (s[i] == '\'' || s[i] == '\"') s.erase(i, 1); // i 没回退!
}
需要保留引号内内容?那就不是“去掉”,而是“提取”
如果目标其实是提取引号之间的子串(比如解析 JSON 片段),直接删引号会破坏结构。此时应使用状态机或正则,而不是无差别删除。
立即学习“C++免费学习笔记(深入)”;
-
std::regex可匹配"[^"]*"或'[^']*',但要注意转义和性能开销 - 简单场景建议手写状态扫描:记录是否在引号内、当前引号类型、遇到转义符(
\')如何处理 - 别混淆“删除分隔符”和“提取被分隔的内容”——前者用
erase,后者必须用解析逻辑
std::erase(C++20)或 remove_if+erase 就够了;真正麻烦的是引号嵌套、转义、跨行等边界情况,那已经不属于“去掉字符”的范畴了。


















