跳到正文
效率工具实用笔记关于本站
效率工具

整理终端长文本:textwrap 换行与缩进的入门做法

约 7 分钟阅读AI 辅助整理

用 textwrap 的 wrap、fill、indent、dedent 处理内存中的英文或简单样例文本,说明各参数作用、输出差异和常见错误,并提醒不保证按中文显示宽度计量。

本文要点

  1. width 参数给的是每行允许的最大字符数,默认 70

  2. 缩进和折行是两件事,textwrap 把它们分开处理

  3. wrap 和 fill 处理的是折行,indent 和 dedent 处理的是整段文本的缩进,两者用途不同

整理终端长文本:textwrap 换行与缩进的入门做法的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先分清 wrap 返回列表、fill 返回整段字符串

如果你要把一段长文本塞进终端宽度里,先决定你要的是“一行一行的列表”还是“拼好的一整段”。

textwrap.wrap(text, width=70) 返回一个字符串列表,每个元素是一行,不含换行符;textwrap.fill(text, width=70) 返回一个字符串,行与行之间用换行符连起来。按官方文档,fill() 就是 "\n".join(wrap(text, ...)) 的简写,两者接受完全相同的关键字参数。

所以选法很简单:后面还要逐行处理(比如加行号、按行判断长度),用 wrap;只想直接打印或写进一个变量,用 fill。

本文只处理内存里的英文或简单样例字符串,不读写文件,也不保证按中文显示宽度计量。下面所有文本都是自建练习示例。

width 是每行上限,长单词默认会被切断

width 参数给的是每行允许的最大字符数,默认 70。textwrap 会尽量在空格处断行,把单词整体挪到下一行,而不是从单词中间切开。

自建示例:

import textwrap

text = "Wrapping text in a terminal is a common task for small tools."

print(textwrap.fill(text, width=30))

输出是每行不超过 30 个字符、在空格处断开的几行。注意两点:

1. 每行长度通常小于 width,因为断点落在空格上,剩下的空间放不下下一个单词。

2. 如果某个单词本身就比 width 长,默认参数 break_long_words=True 会把它切断,以保证没有一行超过 width。文档写的是:只有 break_long_words 设为 false 时,长单词才不被切断,此时该单词单独占一行,这一行可能超出 width。

所以排查“为什么这行特别长”时,先看是不是把 break_long_words 设成了 false,而不是默认行为。

width 只按字符计数,不按显示宽度。中文、全角字符、emoji 在终端里占的列数可能和字符数不一致,本文不保证这类样例的折行结果。

indent 和 subsequent_indent 只管缩进,且计入行宽

缩进和折行是两件事,textwrap 把它们分开处理。

- initial_indent:加在第一行前面的字符串,默认空。文档说明它计入第一行的长度。

- subsequent_indent:加在除第一行之外每一行前面的字符串,默认空。文档说明它计入除第一行外每一行的长度。

自建示例:

import textwrap

text = "Wrapping text in a terminal is a common task for small tools."

print(textwrap.fill(text, width=40, initial_indent="> ", subsequent_indent="  "))

第一行以 "> " 开头,后续行以两个空格开头。关键点:缩进字符串的长度会占用 width 的额度。也就是说,subsequent_indent 越长,留给正文的字符数越少。

这一点决定了缩进要交给 initial_indent 和 subsequent_indent 参数,让 textwrap 在计算断点时就把它们算进去,而不是折行之后再自己往行首拼字符串。

indent 与 dedent:给整段加缩进、去掉公共缩进

wrap 和 fill 处理的是折行,indent 和 dedent 处理的是整段文本的缩进,两者用途不同。

textwrap.indent(text, prefix) 给 text 的每一行加 prefix。文档说明:默认只给不是纯空白的行加前缀(包括行尾换行符在内的整行都算),predicate 参数可以改这个规则。

textwrap.dedent(text) 去掉每一行开头的公共空白。它找的是所有行共有的那段缩进,把它删掉。

自建示例:

import textwrap

block = """
    first line
    second line
"""

print(repr(textwrap.dedent(block)))

去公共缩进后,两行开头的四个空格被删掉。dedent 只删公共部分:如果某行缩进比别人少,它就以最少的那行为准,其余行保留多出来的空格。

一个容易踩的坑:文档明确说,制表符和空格都被当作空白,但两者不相等。所以 " hello" 和 "\thello" 这两行被认为没有公共前导空白,dedent 不会删掉它们前面的空白。排查时先看是不是把 tab 和空格混着用了。

检查结果:打印每行长度和 repr

折行结果对不对,靠肉眼看容易漏掉行尾空格和缩进。建议打印每行长度和 repr。

自建示例:

import textwrap

text = "Wrapping text in a terminal is a common task for small tools."

for w in (40, 20):
    print("width =", w)
    lines = textwrap.wrap(text, width=w, subsequent_indent="  ")
    for line in lines:
        print(len(line), repr(line))
    print()

检查三件事:

1. 每行 len 是否都不超过 width。超了,先确认 break_long_words 是不是被设成了 false,再确认缩进有没有算进 width。

2. 后续行是否都带上了 subsequent_indent。

3. repr 里有没有多余的行尾空格。

如果结果和预期不符,先确认你用的是 wrap 还是 fill,再确认缩进是交给参数还是事后拼接。

使用限制:只处理内存文本,不保证中文宽度

本文的范围只有一条:处理内存里的英文或简单样例字符串。

几个明确限制:

1. textwrap 按字符数计算,不按终端显示列数。中文、全角标点、emoji 的显示宽度和字符数不一致,本文不保证这类文本的折行结果,也不声称与浏览器排版一致。

2. 它不读写文件。要处理文件内容,先自己读进来,处理完再自己写出去。

3. 它不处理制表符对齐,也不管终端实际宽度。终端宽度要自己取,再传给 width。

4. 本文不展开 shorten、max_lines、placeholder 等截断相关参数,也不展开 break_on_hyphens 的细节。

参考资料:Python 官方 textwrap 文档(https://docs.python.org/3/library/textwrap.html)。上面所有示例均为自建练习,不是对真实终端或真实文件的记录。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回效率工具 →