faqts : Computers : Programming : Languages : Python : Snippets

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

11 of 13 people (85%) answered Yes
Recently 8 of 10 people (80%) answered Yes

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()