Entry
Simple module for formatting text into columns
Nov 8th, 2005 15:02
Martin Miller, Nathan Wallace, Hans Nowak, Snippet 329, Hanish Lawson
"""
Packages: text.formatting
"""
"""
Here is TextFormatter, a simple module for formatting text into columns
of specified widths. It does multiline wrapping and supports left,
center and right alignment.
"""
#===================================================================
#!/usr/bin/env python
"""
Provides the TextFormatter class for formatting text into columns.
"""
# File: TextFormatter.py
# Author: Hamish B Lawson
# Date: 19/11/2020
import string
left = 0
center = centre = 1
right = 2
class TextFormatter:
"""
Formats text into columns.
Constructor takes a list of dictionaries that each specify the
properties for a column. Dictionary entries can be:
width the width within which the text will be wrapped
alignment left|center|right
margin amount of space to prefix in front of column
The compose() method takes a list of strings and returns a formatted
string consisting of each string wrapped within its respective column.
Example:
formatter = TextFormatter(
(
{'width': 10},
{'width': 12, 'margin': 4},
{'width': 20, 'margin': 8, 'alignment': right},
)
)
print formatter.compose(
(
"A rather short paragraph",
"Here is a paragraph containing a
veryveryverylongwordindeed.",
"And now for something on the right-hand side.",
)
)
gives:
A rather Here is a And now for
short paragraph something on the
paragraph containing a right-hand side.
veryveryvery
longwordinde
ed.
"""
class Column:
def __init__(self, width=75, alignment=left, margin=0):
self.width = width
self.alignment = alignment
self.margin = margin
self.lines = []
def align(self, line):
if self.alignment == center:
return string.center(line, self.width)
elif self.alignment == right:
return string.rjust(line, self.width)
else:
return string.ljust(line, self.width)
def wrap(self, text):
self.lines = []
words = []
for word in string.split(text):
if len(word) <= self.width:
words.append(word)
else:
for i in range(0, len(word), self.width):
words.append(word[i:i+self.width])
current = words.pop(0)
for word in words:
increment = 1 + len(word)
if len(current) + increment > self.width:
self.lines.append(self.align(current))
current = word
else:
current = current + ' ' + word
self.lines.append(self.align(current))
def getline(self, index):
if index < len(self.lines):
return ' '*self.margin + self.lines[index]
else:
return ' ' * (self.margin + self.width)
def numlines(self):
return len(self.lines)
def __init__(self, colspeclist):
self.columns = []
for colspec in colspeclist:
self.columns.append(apply(TextFormatter.Column, (), colspec))
def compose(self, textlist):
numlines = 0
textlist = list(textlist)
if len(textlist) != len(self.columns):
raise IndexError, "Number of text items does not match columns"
for text, column in map(None, textlist, self.columns):
column.wrap(text)
numlines = max(numlines, column.numlines())
complines = [''] * numlines
for ln in range(numlines):
for column in self.columns:
complines[ln] = complines[ln] + column.getline(ln)
return string.join(complines, '\n') + '\n'
def test():
formatter = TextFormatter(
(
{'width': 10},
{'width': 12, 'margin': 4},
{'width': 20, 'margin': 8, 'alignment': right},
)
)
print formatter.compose(
(
"A rather short paragraph",
"Here is a paragraph containing a veryveryverylongwordindeed.",
"And now for something on the right-hand side.",
)
)
if __name__ == '__main__':
test()