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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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) ) >= 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!" """
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.