最直接的方式是用 std::regex_replace 匹配 {key} 或 ${key} 并替换为空字符串;注意 msvc 2019 及更早版本 regex 有 bug,建议 windows 下改用 find 循环或 boost.regex,gcc/clang 下可用;手动扫描兼容性最强。

用 std::regex_replace 清除形如 {key} 或 ${key} 的占位符
最直接的方式是正则匹配并替换为空字符串。C++11 起支持 std::regex,能覆盖常见占位符格式,比如 {name}、${age}、{_id_} 等。
注意:MSVC 2019 及更早版本的 std::regex 实现有 bug(尤其对重复量词和 Unicode),建议在 Windows 上优先用 std::string::find + 循环,或改用 Boost.Regex;GCC/Clang 下基本可用。
示例(清除 {xxx} 和 ${xxx}):
std::string s = "Hello {name}, welcome to ${place}!";
s = std::regex_replace(s, std::regex(R"(\$\{[^\}]*\}|\{[^\}]*\})"), "");
// 结果: "Hello , welcome to !"
- 正则
R"(\$\{[^\}]*\}|\{[^\}]*\})"同时匹配${...}和{...},避免遗漏 - 用原始字符串字面量
R"(...)"避免反斜杠转义混乱 -
[^\}]*比.*?更安全,防止跨占位符误匹配(如{a}{b}中的{a}{b}被当成一个整体)
手动扫描——兼容性最强、可控性最高的方案
当目标环境不支持可靠正则(嵌入式、旧编译器、性能敏感场景),或占位符规则极简单(只认 {xxx}),手写循环反而更稳、更快、无依赖。
核心逻辑:遍历字符串,跳过所有 { 到 } 之间的内容(含括号本身);其余字符保留。
std::string remove_placeholders(const std::string& s) {
std::string out;
out.reserve(s.size());
size_t i = 0;
while (i
- 不依赖
<regex></regex>,全标准库,C++11 即可 - 遇到不闭合的
{(如"abc{def")会保留原样,不会崩溃或误删 - 若需同时处理
${xxx},只需在if分支中加一个else if (s[i] == '$' && i+1 判断
占位符嵌套?别用正则,也别手动硬解
如果输入可能含嵌套结构(如 {a{b}c}),标准正则引擎无法正确解析(PCRE 可以,但 std::regex 不支持递归),手动扫描也需改用栈模拟。
真实业务中,占位符设计本就不该嵌套。若上游数据真出现嵌套,说明协议或模板系统已失控——这时优先应约束输入源,而非在清洗层兜底。
强行处理嵌套的代价高、易出错,且绝大多数模板引擎(如 Jinja、Handlebars)本身也不允许占位符嵌套。遇到这种情况,先确认是否真的需要支持,而不是默认“应该能处理”。
性能差异大,别在热路径里无脑调 std::regex_replace
正则构造、编译、执行三步开销明显,尤其在短字符串高频调用场景(如日志拼接、HTTP header 构造)。实测显示:对 100 字符以内字符串,手写循环比 std::regex_replace 快 3–8 倍。
- 若占位符格式固定(如只清
{key}),永远优先选find+循环 - 若格式多变且调用频次低(如配置文件一次性加载),用正则更简洁
- 避免每次调用都新建
std::regex对象;提取为static const成员或函数局部静态变量
真正容易被忽略的是:很多人把占位符清理放在日志宏、序列化入口这类高频位置,却没意识到正则正在拖慢整个链路。先测,再选。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











