4

Consider this example:

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))

The string mystr is already a multiline string, given that it contains linebreaks; however, if I run this script, I get as output:

[' 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 ??']

... which means that textwrap.wrap first "joined" the multiline string (that is, removed the existing linebreaks in it), and only then wrapped it (i.e. split it at the given number of characters).

How can I wrap a multiline string, such that the line feeds are preserved? that is, in this case, the expected output would be:

['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 ??']

EDIT; thanks to comment by @u_mulder, I tried:

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

and with that I get:

['\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 ??']

The line breaks seem to be preserved, but as "inline" characters; so here the first element is a multiline string in itself -- and so it is not as I require it, with every line as an array element.

sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 2
    Some similar case, maybe it helps http://stackoverflow.com/questions/12902521/python-textwrap-wrap-causing-issue-with-n – u_mulder Mar 04 '15 at 20:16
  • Thanks @u_mulder - turns out, this is not a duplicate; please see edit in the OP – sdaau Mar 04 '15 at 20:23
  • 1
    Just a side note, the reason the behaviors are not as you expect are that (according to the docs) `pprint - Support to pretty-print lists, tuples, & dictionaries recursively` (not strings). And `help(textwrap.wrap)` gives ` Wrap a single paragraph of text, returning a list of wrapped lines.` So we see it expects a single paragraph in the input string, not several paragraphs. – mtrw Mar 04 '15 at 20:55

2 Answers2

7

Just add the newlines back after splitting:

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)

Output:

['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 ??']
sdaau
  • 36,975
  • 46
  • 198
  • 278
Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70
  • Thanks, @MalikBrahimi - but I don't see how this wraps at say 80 characters? Did you try this at all? – sdaau Mar 04 '15 at 20:16
  • No, I'll have that working in few minutes, give me a little time. – Malik Brahimi Mar 04 '15 at 20:17
  • Many thanks @MalikBrahimi - that works, but the output is exactly the same as in the edit I just made in the OP; that is, if you do `pprint.pprint(mylist)`, you'll see that the first item in the array is a multiline string in itself, it's not one line per element as I wanted it to; any ideas about that? – sdaau Mar 04 '15 at 20:28
  • What exactly do you need as I probably don't understand? Do you want the list now as a string? – Malik Brahimi Mar 04 '15 at 20:31
  • @sdaau - `pprint.pprint(mystr)` (without wrapping) shows '`\nFirst line.\nSecond line.\nThe third ...'`. I think you're falling victim to an expected behavior of `pprint`. – mtrw Mar 04 '15 at 20:32
  • @sdaau Forget about pretty print. Print the list as is, and you'll see the answer. – Malik Brahimi Mar 04 '15 at 20:34
  • Thanks @MalikBrahimi, @mtrw- I want to get the output that I wrote in the OP under "that is, in this case, the expected output would be... " - each line, regardless if it was originally a line or split afterwards, should be a its own item in the array; there should _not_ be an item in the array containing multiple lines, even if they are delimited by `\n` - in that case, there should be _separate_ array entries for each of those lines. – sdaau Mar 04 '15 at 20:35
  • @MalikBrahimi - managed to do what I want; posted an answer below, but it's not as elegant as I'd want it to ... cheers! – sdaau Mar 04 '15 at 20:42
  • 1
    @MalikBrahimi - if you insist on an accept, you should at least be bothered to a) post a fully compilable example, b) post the output - at least if the original poster did so. I edited your answer, and in that form I can accept it (even if I had to answer my question first, in order to edit your question, so I can accept it). Cheers! – sdaau Mar 04 '15 at 21:15
2

Ok, I think I found how to do what I want, but its kind of unelegant:

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)

This results with:

['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 ??']

So:

  • 1st elem: 'First line.' which was originally defined
  • 2nd elem: 'Second line.' which was also originally defined
  • 3rd elem: original third line was too long, so it is wrapped at 80 characters, first part of it is the 3rd element in the array
  • 4th elem: contains the second part of the wrap of the original third line

That is what I wanted to achieve; note that this is a very different situation than when the first element in the array contains multiple lines, as in ['\nFirst line.\nSecond line.\nThe third line ....

sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 2
    Your solution is quite nice. You can simplify the code a bit by removing the `ifs`. Just: `for ix in mystr.splitlines(): aa += textwrap.wrap(ix,80)` gives the same result. – mtrw Mar 04 '15 at 20:53