Python word wrap function
Update 2008-09-18: I just found out there is a textwrap
module in the Python Standard Library. See the docs at: http://docs.python.org/lib/module-textwrap.html.
I'm working on creating function headers for our C development code. These headers include the function name, a purpose statement, input/output lists, etc. So my solution (because I'm lazy and prefer scripting to writing hundreds of lines of not-actually-code) is to write a Python script to write the headers. I put all the pertinent information (function names, variable names, descriptions, etc.) in an Excel spreadsheet and I'm using Python to read the data and properly format it. (See here and here for more info on using Python w/ Excel.) Things are going pretty well. The spreadsheet (and the script) are getting a little messy, but overall, it is faster (I think), more fun (definitely) and I believe will produce more consistent results. It also allows me to be more flexible if names or descriptions change in the future because I only need to change the information once in the spreadsheet instead of mutiple places in the actual .c files.
One of the rules for the function headers is that they must be 80 columns or less in width. It is annoying to wrap everything by hand so I wrote a Python function to do the wrapping. (I know Emacs could probably do all this in about 2 lines of Lisp, but I haven't learned that much yet.) Here is the script with a couple of examples:
def word_wrap(string, width=80, ind1=0, ind2=0, prefix=''):
""" word wrapping function.
string: the string to wrap
width: the column number to wrap at
prefix: prefix each line with this string (goes before any indentation)
ind1: number of characters to indent the first line
ind2: number of characters to indent the rest of the lines
"""
string = prefix + ind1 * " " + string
newstring = ""
while len(string) > width:
# find position of nearest whitespace char to the left of "width"
marker = width - 1
while not string[marker].isspace():
marker = marker - 1
# remove line from original string and add it to the new string
newline = string[0:marker] + "\n"
newstring = newstring + newline
string = prefix + ind2 * " " + string[marker + 1:]
return newstring + string
string = "PURPOSE: To end world hunger, create peace for all people, solve all technological and scientific problems, make an exorbitant amount of money, and remain humble in the process."
print word_wrap(string, 60)
PURPOSE: To end world hunger, create peace for all people, solve all technological and scientific problems, make an exorbitant amount of money, and remain humble in the process.Example 2: wrap at 60 chars, with a prefix, and a hanging indent
print word_wrap(string, 60, 0, 9, " * ")
* PURPOSE: To end world hunger, create peace for all * people, solve all technological and scientific * problems, make an exorbitant amount of money, * and remain humble in the process.
Comments
Thank you for the code! I've used it in a small program I created - pietweet, a twitter client for python /commandline.
http://harshadsharma.com/doku.php/software:pietweet
Cheers!
Harshad,
I'm glad it was useful for you. Pietweet looks like a cool program.
The python tetwrap module doesn't allow multiple paragraphs.
You mention emacs, but not knowing how to do it. The feature you want is built into emacs. Mark the buffer and then hit Alt-q (or M-q for the purists)
Ed, thanks for the Emacs tip. I would do good to remember that keybinding!
It's an old post, but...
Get rid of the 'if'.
while len(string) > width:
is enough.
In other words...
12 s/if/while/
13 d
14,22 s/^\t//
23,26 d
Arthur Dent: That makes the code much cleaner! I don't know what I was thinking. I made the change above. Thanks for the tip.
textwrap is more flexible and can handle with strings without spaces that > width (URLs for example) http://docs.python.org/library/textwrap.html
import textwrap
wrapper = textwrap.TextWrapper(width=80,
initial_indent=" " * 4,
subsequent_indent=" " * 4,
break_long_words=False,
break_on_hyphens=False)
string = "my non-wraped string"
print wrapper.fill(string)
winterheart: I agree the textwrap module should be used if possible.
I ran your example:
import textwrap
wrapper = textwrap.TextWrapper(width=80,
initial_indent=" " * 4,
subsequent_indent=" " * 4,
break_long_words=False,
break_on_hyphens=False)
string = "PURPOSE: To end world hunger, create peace for all people, solve all technological and scientific problems, make an exorbitant amount of money, and remain humble in the process."
print wrapper.fill(string)
And got the following output:
PURPOSE: To end world hunger, create peace for all people, solve all
technological and scientific problems, make an exorbitant amount of money,
and remain humble in the process.
Thanks.