c++oding="utf-8" ?>
std::regex_replace 可直接清除 ansi 转义序列,推荐使用原始字符串 r"(\x1b[[0-9;]*m)" 匹配并替换为空;对 windows 控制字符或禁用正则环境,需手动遍历过滤 c0 字符(0–31,排除\t\n\r)。

用 std::regex_replace 清除带格式的标记(如 ANSI 转义序列)
如果你要删的是终端显示用的 ANSI 颜色码(比如 \x1b[31m、\x1b[1;32m),std::regex_replace 是最直接的选择。C++11 起标准库就支持,不用额外依赖。
注意:默认 std::regex 在某些编译器(如 libstdc++ 旧版本)上对 Unicode 或复杂转义支持较弱,建议用字面量字符串避免反斜杠被误解析。
- 匹配 ANSI 序列的正则:用原始字符串
R"(\x1b\[[0-9;]*m)"—— 注意\x1b是 ESC 字符,[0-9;]*匹配中间任意数字和分号组合 - 替换为空字符串:
std::regex_replace(s, std::regex(R"(\x1b\[[0-9;]*m)"), "") - 如果字符串里还混着 Windows 控制台 API 的
\x0f、\x0e等,得额外加一条 regex 替换
手动遍历跳过 ANSI 序列(不依赖 std::regex)
有些嵌入式或精简环境禁用正则,或者你只处理 ANSI 码且想零开销。这时手动扫描更可控、更快。
核心逻辑是:遇到 \x1b 就判断后面是否跟 [,再跳过所有数字、分号直到 m;否则保留当前字符。
- 用
std::string::iterator双指针遍历,避免重复构造子串 - 必须检查边界:读
[前先确认还有下一个字符,读m前确保没越界 - 别漏掉类似
\x1b[0K(清行)或\x1b[2J(清屏)这类非m结尾的控制序列——按需扩展判断结尾字符集
处理 Windows 控制台样式(SetConsoleTextAttribute 对应的不可见标记)
Windows 上某些程序(尤其 PowerShell 或 .NET 工具输出)会插入 \x00 到 \x1f 区间的控制字符,这些不是 ANSI,std::regex 默认模式也匹配不到。
它们通常不参与显示,但会影响字符串长度计算或后续解析(比如 JSON 解析失败)。这时候不能靠正则猜,得明确过滤范围。
- 若确定只需剔除 C0 控制字符(ASCII 0–31,不含
\t、\n、\r),可写循环检查:c > 0 && c - 注意
\x7f(DEL)有时也被当控制符处理,按实际输入源决定是否一并过滤 - 别用
std::isprint直接过滤——它在不同 locale 下行为不一致,且会误杀中文等多字节字符
为什么 std::erase_if 不适合直接删 ANSI 序列
std::erase_if 是按单个字符判断的,而 ANSI 序列是多字节组合(最少 3 字节:\x1b[0m),没法拆成独立字符处理。
强行用它会导致只删掉 \x1b 或 [,留下残缺序列(如 31m),后续显示可能错乱。
- 错误示范:
std::erase_if(s, [](char c) { return c == '\x1b'; });—— 只删 ESC,没用 - 正确思路:要么用正则整体替换,要么手写状态机跳过整段
- 如果真想用泛型算法,得自己写一个按“token”粒度操作的 erase 函数,但复杂度远超直接遍历
最麻烦的其实是混合场景:一段日志里同时有 ANSI 转义、Windows 控制字符、甚至自定义的 {red}...{/red} 标签。这种时候别硬塞进一个正则,分阶段清理更稳——先清控制字符,再清自定义标签,最后做空格规整。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











