标准库无直接center函数,可用insert和substr手动实现居中填充:先计算左右填充数(左补数=(总宽-原长)/2,右补数=总宽-左补数-原长),再前后插入;或用ostringstream配合setw、setfill输出居中效果。

std::string::insert 和 std::string::substr 配合实现居中填充
标准库没有直接叫 center 的函数,但用 insert 和 substr 拼出来最可控,也最容易调试。核心思路是:先算左右两边各需补多少个填充字符,再插入到原字符串前后。
常见错误是忽略奇偶长度导致偏移一格——比如总宽 10、原串长 3,左右应各补 3 个(3+3+3=9),剩 1 个得加在右边才视觉居中。所以右补数 = 总宽 - 左补数 - 原长。
- 左补数 = (总宽 - 原串长度) / 2,整除向下取整
- 右补数 = 总宽 - 左补数 - 原串长度
- 填充字符默认用空格,但可传入任意
char,比如'*'
示例:std::string s = "abc"; s.insert(0, 3, '*').append(4, '*'); → "***abc****"(总宽 10)
用 std::ostringstream + std::setw + std::setfill 更简洁
如果只是输出到控制台或日志,std::ostringstream 配合 std::setw 和 std::setfill 是最短路径,且自动处理对齐逻辑。
注意:std::setw 只对紧邻的下一个输出项生效,且不修改原字符串,只影响流输出行为。想拿到居中后的字符串,必须用 str() 提取。
-
std::setw(n)设定字段宽度,不足时用setfill补 - 默认右对齐,要居中得手动拆成三段:
left_fill + content + right_fill - 别漏掉
#include <iomanip></iomanip>,否则编译报错‘setw’ was not declared in this scope
示例:
std::ostringstream oss;<br>oss std::string result = oss.str(); // 得到 "**abc*****" —— 这是右对齐,不是居中所以真要居中,还是得自己算左右填充量。
第三方库如 fmt 或 abseil 的 center 接口怎么用
fmt 库提供了 fmt::format("{:^10}", "abc"),语法和 Python 一致,^ 表示居中,10 是总宽。abseil 有 absl::StrFormat("%*s", width, str) 但不直接支持居中,得套一层逻辑。
用 fmt 的前提是已接入 C++20 之前的项目,且愿意引入外部依赖。它的优势是类型安全、无缓冲区溢出风险;劣势是编译时间略长,且 {:^10} 中的 10 必须是编译期常量,动态宽度得拼格式串:fmt::format("{{:^{}}}", width) 再调用 fmt::format(fmt_str, "abc")。
- 动态宽度写法容易漏掉双大括号转义,写成
"{:^{}}" → 编译失败 - fmt 默认填充空格,换字符要写
{:*^10},星号在^前 - 链接时需加
-lfmt,CMake 要 find_package(fmt REQUIRED)
性能敏感场景下避免临时字符串拷贝
如果在高频循环里反复做居中(比如渲染每帧 UI 文本),每次构造新 std::string 会触发堆分配。这时建议预分配缓冲区,用 resize + replace 原地填充。
关键点:提前知道最大宽度,复用同一块内存;用 std::string::replace 替换首尾区间,比多次 insert 和 append 少一次 realloc。
- 先
s.resize(total_width, fill_char),填满整个缓冲区 - 再
s.replace(left_pad, content.length(), content) - 注意
left_pad是起始位置,不是长度;content.length()是替换长度 - 若 content 比 total_width 长,
replace会截断,需提前判断
这招在嵌入式或游戏引擎里很实用,但普通业务代码没必要,可读性反而下降。
真正麻烦的不是算法本身,而是“居中”在不同上下文含义不同:终端显示要考虑全角/半角字符宽度,GUI 渲染要看字体度量,日志打印可能还要兼容 ANSI 颜色码——这些都会让填充数失效。动手前先确认你的“宽度”单位到底是字节数、字符数,还是像素。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











