在Python中如何包装多行字符串(保留现有的换行符)?

4

考虑以下例子:

import textwrap
import pprint

mystr=r"""
First line.
Second line.
The third line is a very long line, which I would like to somehow wrap; wrap at 80 characters - or less, or more! ... can it really be done ??"""

pprint.pprint(textwrap.wrap(mystr,80))

字符串mystr已经是一个多行字符串,因为它包含换行符;但是,如果我运行这个脚本,我会得到以下输出:

[' First line. Second line. The third line is a very long line, which I would like',
 'to somehow wrap; wrap at 80 characters - or less, or more! ... can it really be',
 'done ??']

这意味着textwrap.wrap首先“连接”多行字符串(即删除其中的现有换行符),然后才将其包装(即在给定的字符数处分割它)。

我如何包装一个多行字符串,以保留换行符?也就是说,在此情况下,预期输出应该是:

['First line.', 
 'Second line.', 
 'The third line is a very long line, which I would like to somehow wrap; wrap at',
 '80 characters - or less, or more! ... can it really be done ??']

编辑:感谢 @u_mulder 的评论,我尝试了以下方法:

textwrap.wrap(mystr,80,replace_whitespace=False)

并且我获得了:
['\nFirst line.\nSecond line.\nThe third line is a very long line, which I would like',
 'to somehow wrap; wrap at 80 characters - or less, or more! ... can it really be',
 'done ??']

换行符似乎被保留了,但作为“内联”字符;因此,这里的第一个元素本身是多行字符串——所以它不像我需要的那样,每一行都作为一个数组元素。


2
一些类似的案例,也许可以帮助 http://stackoverflow.com/questions/12902521/python-textwrap-wrap-causing-issue-with-n - u_mulder
谢谢 @u_mulder - 原来这不是一个重复的问题,请查看原帖中的修改。 - sdaau
1
只是一点小提示,行为不如您所期望的原因是(根据文档)pprint - 支持递归地漂亮打印列表、元组和字典(而不是字符串)。并且 help(textwrap.wrap) 给出了 将单个段落文本包装起来,返回一个包含已包装行的列表。 因此我们可以看到它期望输入字符串中只有一个段落,而不是多个段落。 - mtrw
2个回答

7

分割后,只需添加回车即可:

import textwrap
import pprint
import itertools

mystr=r"""
First line.
Second line.
The third line is a very long line, which I would like to somehow wrap; wrap at 80 characters - or less, or more! ... can it really be done ??"""

wrapper = textwrap.TextWrapper(width = 80)
mylist = [wrapper.wrap(i) for i in mystr.split('\n') if i != '']
mylist = list(itertools.chain.from_iterable(mylist))

pprint.pprint(mylist)

输出:

['First line.',
 'Second line.',
 'The third line is a very long line, which I would like to somehow wrap; wrap at',
 '80 characters - or less, or more! ... can it really be done ??']

不,我会在几分钟内让它工作的,请给我一点时间。 - Malik Brahimi
非常感谢@MalikBrahimi - 这个方法很有效,但输出结果与我刚刚在原始帖子中所做的编辑完全相同;也就是说,如果你执行pprint.pprint(mylist),你会发现数组中的第一项本身就是一个多行字符串,而不是像我想要的每个元素一行;对此有什么想法吗? - sdaau
你需要什么?我可能不太明白。你现在想要把列表转换成字符串吗? - Malik Brahimi
@MalikBrahimi - 成功做到了我想要的;下面发布了一个答案,但不如我所希望的那么优雅...干杯! - sdaau
1
@MalikBrahimi - 如果你坚持要接受,那么你至少应该费心地:a)发布一个完全可编译的示例,b)发布输出结果 - 至少如果原始帖子这样做了。我编辑了你的答案,在那种形式下我可以接受它(即使我必须先回答我的问题,以便编辑你的问题,这样我才能接受它)。干杯! - sdaau
显示剩余4条评论

2

好的,我想我找到了如何做我想要的事情,但这种方法有点不太优雅:

import textwrap
import pprint

mystr=r"""
First line.
Second line.
The third line is a very long line, which I would like to somehow wrap; wrap at 80 characters - or less, or more! ... can it really be done ??"""

#pprint.pprint(textwrap.wrap(mystr,80,replace_whitespace=False))

aa=[]
for ix in mystr.splitlines():
  if ix:
    if len(ix)<=80: aa.append(ix)
    else: aa.extend(textwrap.wrap(ix,80))

pprint.pprint(aa)

这将导致:
['First line.',
 'Second line.',
 'The third line is a very long line, which I would like to somehow wrap; wrap at',
 '80 characters - or less, or more! ... can it really be done ??']

所以:

  • 第一个元素:'First line.',最初定义
  • 第二个元素:'Second line.',也是最初定义的
  • 第三个元素:原始的第三行太长了,因此在80个字符处换行,第一部分成为数组中的第三个元素
  • 第四个元素:包含原始第三行换行的第二部分

这就是我想要实现的;请注意,这与数组中第一个元素包含多行的情况非常不同,例如['\nFirst line.\nSecond line.\nThe third line ...


2
你的解决方案非常好。你可以通过删除 ifs 来简化代码。只需使用 for ix in mystr.splitlines(): aa += textwrap.wrap(ix,80) 即可得到相同的结果。 - mtrw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接