views:

77

answers:

3

I'm trying to format some strings for output on the command-line, report style, and am looking for the easiest method to format a string such that I can get automatic paragraph formatting.

In perlform formatting is done through the "format" function

format Something =
    Test: @<<<<<<<< @||||| @>>>>>
            $str,     $%,    '$' . int($num)
.

$str = "widget";
$num = $cost/$quantity;
$~ = 'Something';
write;

Variations of the perlform allow texts to be wrapped cleanly, useful for help screens, log reports and such.

Is there a python equivalent? Or a reasonable hack that I could write using Python's new string format function?

Example output I'd like:

Foobar-Title    Blob
  0123          This is some long text which would wrap
                past the 80 column mark and go onto the
                next line number of times blah blah blah.
  hi there      dito
  something     more text here. more text here. more text
                here.
+1  A: 

There is this from python documents and this that might help.

Kyra
@Kyra - This formatter lib may do the trick! Didn't know about it at all, I'm trying it out now.
Petriborg
@Petriborg - Good Luck :D
Kyra
This is the python doc for the textwrap -- http://docs.python.org/library/textwrap.html
Petriborg
+2  A: 
import textwrap
import itertools

def formatter(format_str,widths,*columns):
    '''
    format_str describes the format of the report.
    {row[i]} is replaced by data from the ith element of columns.

    widths is expected to be a list of integers.
    {width[i]} is replaced by the ith element of the list widths.

    All the power of Python's string format spec is available for you to use
    in format_str. You can use it to define fill characters, alignment, width, type, etc.

    formatter takes an arbitrary number of arguments.
    Every argument after format_str and widths should be a list of strings.
    Each list contains the data for one column of the report.

    formatter returns the report as one big string.
    '''
    result=[]
    for row in zip(*columns):
        lines=[textwrap.wrap(elt, width=num) for elt,num in zip(row,widths)]
        for line in itertools.izip_longest(*lines,fillvalue=''):
            result.append(format_str.format(width=widths,row=line))
    return '\n'.join(result)

For example:

widths=[17,41]
form='{row[0]:<{width[0]}} {row[1]:<{width[1]}}'

titles=['Foobar-Title','0123','hi there','something']
blobs=['Blob','This is some long text which would wrap past the 80 column mark and go onto the next line number of times blah blah blah.','dito','more text here. more text here. more text here.']

print(formatter(form,widths,titles,blobs))

yields

# Foobar-Title      Blob                                     
# 0123              This is some long text which would wrap  
#                   past the 80 column mark and go onto the  
#                   next line number of times blah blah blah.
# hi there          dito                                     
# something         more text here. more text here. more text
#                   here.                                    

formatter can take an arbitrary number of columns.

unutbu
Thanks @unutbu this is also a clear example now. Wish I could accept more then one answer, lol.
Petriborg
+2  A: 

There isn't automatic formatting like this built into Python. (The .format function syntax is borrowed from C#.) After all, Perl was "Practical Extraction and Report Language" and Python isn't designed for formatting reports.

Your output could be done with the textwrap module, e.g.

from textwrap import fill
def formatItem(left, right):
   wrapped = fill(right, width=41, subsequent_indent=' '*15)
   return '  {0:<13}{1}'.format(left, wrapped)

...

>>> print(formatItem('0123', 'This is some long text which would wrap past the 80 column mark and go onto the next line number of times blah blah blah.'))
  0123         This is some long text which would wrap
               past the 80 column mark
               and go onto the next line
               number of times blah blah
               blah.

Note that this assumes the "left" does not span over 1 line. A more general solution would be

from textwrap import wrap
from itertools import zip_longest
def twoColumn(left, right, leftWidth=13, rightWidth=41, indent=2, separation=2):
    lefts = wrap(left, width=leftWidth)
    rights = wrap(right, width=rightWidth)
    results = []
    for l, r in zip_longest(lefts, rights, fillvalue=''):
       results.append('{0:{1}}{2:{5}}{0:{3}}{4}'.format('', indent, l, separation, r, leftWidth))
    return "\n".join(results)

>>> print(twoColumn("I'm trying to format some strings for output on the command-line", "report style, and am looking for the easiest method to format a string such that I can get automatic paragraph formatting."))
  I'm trying to  report style, and am looking for the
  format some    easiest method to format a string such
  strings for    that I can get automatic paragraph
  output on the  formatting.
  command-line   
KennyTM
Excellent, A very clear example thanks.
Petriborg