合理的 word wrap 是在空格或标点处断行、不拆单词、每行长度不超过指定宽度的文本折行方式;需逐词扫描并累积行缓冲,对中文等需按显示宽度(非字节长度)计算,unicode 处理需解码或借助 boost.text 等库。

什么是合理的 word wrap?不是简单按字符截断
直接用 substr 每 n 个字符切一刀,会把单词从中间劈开,比如 "hello world" 宽度设为 5,就可能变成 "hell\no wo\nrld" —— 这不是人想要的折行。真正的 word wrap 要在空格(或标点)处断行,同时保证每行 ≤ 指定宽度,且不拆单词(除非单个单词本身超长)。
手动实现核心逻辑:逐词扫描 + 行缓冲累积
标准库没提供现成函数,得自己写。关键思路是把字符串按空格切分成词(std::istringstream 或 std::string::find_first_of),再逐个尝试加入当前行:
- 若当前行为空,直接加词
- 否则检查:
current_line.length() + 1 + next_word.length() (+1 是空格位) - 满足就追加空格+词;不满足就 push 当前行,重置 current_line 为 next_word
- 遇到超长词(
word.length() > width),只能强制折断——用word.substr(0, width)和剩余部分递归处理
示例片段:
std::vector<:string> wrap(const std::string& s, size_t width) {
std::vector<:string> lines;
std::istringstream iss(s);
std::string word, line;
while (iss >> word) {
if (line.empty()) {
line = word;
} else if (line.length() + 1 + word.length()
<h3>处理中文、全角字符和混合文本时的坑</h3>
<p>C++ 的 <code>std::string::length()</code> 返回字节数,不是显示宽度。中文字符通常是 UTF-8 编码(3 字节),但显示占 2 个英文字符宽度。如果按字节算宽度,一行最多放 20 字节 ≠ 最多放 20 个英文字符 ≠ 最多放 ~6 个汉字。</p>
<ul>
<li>若需按「显示宽度」折行(如终端输出),必须先做 UTF-8 解码,用 <code>std::mbstowcs</code> 或第三方库(如 ICU、utf8cpp)计算每个字符的列宽</li>
<li>简单方案:假设所有非 ASCII 字符占 2 列,ASCII 字符占 1 列,手写宽度计算器</li>
<li>错误写法:<code>if (line.length() + ... —— 这对中文完全失效</code>
</li>
<li>更糟的是:某些字体里中文标点(,。!)也占 2 列,但英文标点只占 1 列</li>
</ul>
<h3>要不要用 Boost 或 fmt?权衡点在哪</h3>
<p><code>Boost.Text</code> 提供了 <code>boost::text::wrap</code>,支持 Unicode 和自定义断行策略,但引入整个 Boost 太重;<code>fmt::format</code> 没内置 wrap 功能,别被名字误导。</p>
<ul>
<li>纯 C++17/20 项目,没外部依赖 → 手写上面逻辑最可控</li>
<li>已用 Boost 且需要处理日文/韩文/双向文本 → <code>boost::text::wrap</code> 值得接入</li>
<li>只是临时调试打印 → 用 Python 脚本预处理反而更快</li>
<li>注意:Boost.Text 不是 header-only,需编译链接,CMake 中要显式 find_package(boost_text)</li>
</ul>
<p>真正难的不是切分,而是宽度定义本身——你得先说清“宽度”指字节、Unicode 码点,还是终端列数,再决定怎么算。</p></:string></:string>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











