ASPN ActiveState Programmer Network  
ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: one-liner word-wrap function
Submitter: Mike Brown (other recipes)
Last Updated: 2004/10/12
Version no: 1.5
Category: Text

 

4 stars 12 vote(s)


Description:

This word-wrap function flows paragraphs of text so they fit in a certain column width. It differs from similar methods in that it preserves existing whitespace such as newlines and runs of spaces.

Source: Text Source

def wrap(text, width):
    """
    A word-wrap function that preserves existing line breaks
    and most spaces in the text. Expects that existing line
    breaks are posix newlines (\n).
    """
    return reduce(lambda line, word, width=width: '%s%s%s' %
                  (line,
                   ' \n'[(len(line)-line.rfind('\n')-1
                         + len(word.split('\n',1)[0]
                              ) >= width)],
                   word),
                  text.split(' ')
                 )

# 2 very long lines separated by a blank line
msg = """Arthur:  "The Lady of the Lake, her arm clad in the purest \
shimmering samite, held aloft Excalibur from the bosom of the water, \
signifying by Divine Providence that I, Arthur, was to carry \
Excalibur. That is why I am your king!"

Dennis:  "Listen. Strange women lying in ponds distributing swords is \
no basis for a system of government. Supreme executive power derives \
from a mandate from the masses, not from some farcical aquatic \
ceremony!\""""

# example: make it fit in 40 columns
print(wrap(msg,40))

# result is below
"""
Arthur:  "The Lady of the Lake, her arm
clad in the purest shimmering samite,
held aloft Excalibur from the bosom of
the water, signifying by Divine
Providence that I, Arthur, was to carry
Excalibur. That is why I am your king!"

Dennis:  "Listen. Strange women lying in
ponds distributing swords is no basis
for a system of government. Supreme
executive power derives from a mandate
from the masses, not from some farcical
aquatic ceremony!"
"""

Discussion:

Most word-wrap functions assume that you have line breaks where you don't want them, so they completely reflow the text. I needed to do some simple word wrapping, and I also wanted to be able to preserve line breaks and runs of spaces that were already present.

This version (v1.5, 2004-10-12), the first update in over two years, incorporates a minor efficiency improvement from Matthias Urlichs.

Known issue: If a line needs to be wrapped in the middle of a run of spaces, there is a chance you will lose a space. This shouldn't matter in most situations, but I thought I'd mention it since I claimed that whitespace is preserved.

How does it work? Well, the reduce function takes each word and adds it to the text to be output, preceding the word with either a space or a linefeed, depending on whether the space + the word would make the current line of the output exceed the max width. Each word is found with a simple split on the space character, so a "word" may actually span multiple lines (which is why existing line breaks end up being preserved). In such cases, only the length of the word's first line is used in the overflow determination.



Add comment

Number of comments: 7

Nested scopes., Jørgen Cederberg, 2002/09/05
Apperently you need to import nested scopes in Python versions before 2.2, i.e. from __future__ import nested_scopes.
Otherwise, this is an excellent function.
Add comment

fixed, Mike Brown, 2002/09/14
I've edited the recipe, adding "width=width" to the anonymous function's signature. This should work better than importing from __future__, as that would only work in Python 2.1.
Add comment

Another fix, Mike Brown, 2002/12/19
As noted above, until today, the function had a bug that sometimes caused premature line breaks. My apologies. It's fixed now, at a cost of some speed.
Add comment

small inefficiency, Matthias Urlichs, 2004/02/18
The code

len(line[line.rfind('\n')+1:])
actually makes a temporary copy of the last word, only to throw it away immediately.
Better:
len(line)-line.rfind('\n')-1

Add comment

another CJK supported unicode word-wrap function, Junyong Pan, 2004/12/10
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/358117
Add comment

Don't use this for long inputs, Guido van Rossum, 2006/10/03
It's code like this that gives reduce() a bad name. :-/ The code is both inscrutable and quadratic.
Add comment

textwrap is in the standard library, Thomas Guettler, 2007/08/23
Hi, Python has a textwrap module in the standard library:
http://docs.python.org/lib/module-textwrap.html
Add comment



Highest rated recipes:

1. A simple XML-RPC server

2. Web service accessible ...

3. a friendly mkdir()

4. SOLVING THE METACLASS ...

5. Povray for python

6. Changing return value ...

7. Implementation of sets ...

8. bag collection class

9. deque collection class

10. Floating Point Simulator




Privacy Policy | Email Opt-out | Feedback | Syndication
© 2006 ActiveState Software Inc. All rights reserved.