Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrap multiline string (preserving existing linebreaks) in Python?

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.

like image 719
sdaau Avatar asked Mar 16 '23 20:03

sdaau


2 Answers

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 ??']
like image 175
Malik Brahimi Avatar answered Mar 20 '23 03:03

Malik Brahimi


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

like image 31
sdaau Avatar answered Mar 20 '23 04:03

sdaau