Reputation: 181
Python 3 can easily handle printing a lot of text:
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vitae odio quis felis consectetur blandit. Etiam mattis vehicula ex id sodales. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris fermentum semper nisi vel aliquam. Ut nec facilisis lectus. Maecenas auctor blandit condimentum. Donec finibus orci ac imperdiet congue. Pellentesque sem leo, commodo non metus ac, posuere maximus lorem. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. "
print(text)
The problem is that this text is printed like this:
This is of course not very good for readability of the text. Going through all of the text by hand to insert white lines makes for quite a hassle. I have seen this question, but I'm wondering if there's an option to do this automatically.
Upvotes: 5
Views: 6397
Reputation: 155458
As mentioned in the comments, pprint
and textwrap
can be used to align output to a given width. Given that, the only trick is determining the width to use. You could just use 78 or 80 and assume the window is that large, but that means bad wrapping if the terminal is smaller, and wasted space if it's larger.
To check the actual width for use with pprint
/textwrap
, if you're on Python 3.3 or higher, you can use shutil.get_terminal_size
:
import shutil
def get_terminal_columns():
return shutil.get_terminal_size().columns
If you can't use 3.3+, you can use the curses
module to determine the size in a somewhat more complicated way:
import curses
def get_terminal_columns():
try:
# Initialize curses for terminal and check dimensions
rows, cols = curses.initscr().getmaxyx()
finally:
# Unload curses to release control of terminal so it behaves normally
curses.endwin()
return cols
Using one of these functions, you can then define:
from __future__ import print_function # Only needed on Py2
import textwrap
def print_autobreak(*args, sep=' '):
width = get_terminal_columns() # Check size once to avoid rechecks per "paragraph"
# Convert all args to strings, join with separator, then split on any newlines,
# preserving line endings, so each "paragraph" wrapped separately
for line in sep.join(map(str, args)).splitlines(True):
# Py3's print function makes it easy to print textwrap.wrap's result as one-liner
print(*textwrap.wrap(line, width), sep="\n")
This automatically performs line breaking between words based on the terminal size, preserves existing "hard" newlines and spaces, and (partially) matches the behavior of print
by allowing multiple arguments with an optional separator. It needs to completely realize the output string before printing (the original print
can print one-by-one, reducing memory usage a bit for huge outputs), but that's a side-effect of performing appropriate global wrapping.
If you need more complete line breaking handling (so two prints can occur without newlines, yet the second one accounts for the length of the first), you'll need a more stateful printer (to remember used characters on a line) or invent something a tad more complex with full curses
functionality. I'll leave that as an exercise.
Upvotes: 8
Reputation: 1016
You might have a look at this Gist.
Then using the returned values to split the string in subsequent print
calls accordingly.
IDLE shell:
Width can be retrieved with sys.stdout.shell.width and that will raise an AttributeError on any other environment (in which case you would use the gist)
Upvotes: 1
Reputation: 148975
The hard part will be to get the size of the console (Windows world) or terminal (Unix), because I know no portable way to get it. It involves (as shown in the Gist proposed by @MaximeB):
GetConsoleScreenBufferInfo
from windows API for Windows (via ctypes.windll
fcntl.ioctl
on Linux or other Unixesnot speaking of possible corner cases... But the Gist could be enough for your requirements if you only use Windows.
Once you have found the width, of if you can accept a static width of 72 or 80 or any other value, the texwrap module can do the trick:
for i in textwrap.wrap(text, 72):
print i
gives:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent vitae
odio quis felis consectetur blandit. Etiam mattis vehicula ex id
sodales. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris
fermentum semper nisi vel aliquam. Ut nec facilisis lectus. Maecenas
auctor blandit condimentum. Donec finibus orci ac imperdiet congue.
Pellentesque sem leo, commodo non metus ac, posuere maximus lorem. Class
aptent taciti sociosqu ad litora torquent per conubia nostra, per
inceptos himenaeos.
Upvotes: 2