This is a function that attempts to fairly tabulate text output into a finite number of columns. It was written with an eye to output on a text-only console. Run the tester function for an example of usage.
def pad (string, length=10, char=" "): """ This function returns a string of length 'length' that consists of the original string 'string' padded with instances of 'char' to the length of 'length' """ string = str(string) if len(string) > length or len(char) > 1: return string strlen = len(string) padlen = abs(length - strlen) string = string + (char * padlen) return string def print_table(lines, header=None, totalwidth=80, mincol=4, splitter=("|", "-", "+")): """ This function dynamically draws a table, trying its best to resize the data to be properly viewed within specified constraints. totalwidth is the total number of horizontal characters that the table is allowed to consume mincol is the minimum number of characters a column may be wide. Note that table will still exceed totalwidth if there is no way to chop it without going beneath mincol """ splitter, horiz, cross = splitter # cheap hack for people who specify the splitter as "" if splitter == "": splitter = " " # cheap hack for people who specify the splitter as "" if horiz == "": horiz = " " # cheap hack for people who specify the splitter as "" if cross == "": cross = " " width = {} total = {} # keep the total length here to calculate averages average = {} fair_average = {} # first thing, figure out the width of each column if header: col = 0 for each in header: width[col] = len(each) col += 1 num_lines = 0 for line in lines: col = 0 num_lines += 1 for each in line: try: if len(each) > width[col]: width[col] = len(each) except: width[col] = len(each) try: total[col] += len(each) except: total[col] = len(each) col += 1 # as a side effect, we now know the number of columns... num_columns = col #figure out an equitable split... total_of_averages = 0 for x in range(0,num_columns): average[x] = int( total[x]/num_lines ) total_of_averages += average[x] total_of_widths = 0 for x in range(0, num_columns): total_of_widths += width[x] amount_of_padding = (num_columns * len(splitter)) + len(splitter) if total_of_widths + amount_of_padding > totalwidth: # we are over our limit... we need to cut some stuff. # so, what we do, is give everyone a % share based on their percentage. for x in width: percent = float(average[x])/(total_of_averages) fair_average[x] = int((totalwidth - amount_of_padding) * percent) # the fair_average[] array now exists. now we see if any are smaller than min_col # if they are... then they need to steal some from the others. total_diff = 0 for x in fair_average: if fair_average[x] < mincol: difference = mincol - fair_average[x] total_diff += difference fair_average[x] = mincol if total_diff > 0: # we stole some bits... they need to go back in somewhere. while total_diff > 0: stole_some = False for x in fair_average: if fair_average[x] > mincol: fair_average[x] -= 1 total_diff -= 1 if not stole_some: break width = fair_average # at this point, the width array knows how wide things should be. buffer = [] if header: col = 0 linebuffer = "" divider = "" for each in header: tmp=each if len(each) > width[col]: tmp = each[0:width[col]] linebuffer += splitter + pad(tmp, width[col]) divider += cross + horiz * width[col] col += 1 linebuffer += splitter divider += cross buffer.append(linebuffer) buffer.append(divider) for line in lines: linebuffer = "" col = 0 for each in line: tmp = each if len(each) > width[col]: #tmp = each[0:width[col]] tmp = each[0:width[col]-2] + ".." linebuffer += splitter + pad(tmp, width[col]) col += 1 linebuffer += splitter buffer.append(linebuffer) return buffer def print_table_tester(): """ throwaway test function for print_table """ testheader = ["name", "address", "telephone", "ass"] data = [] data.append(["Bob Smithers", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["Bob Fuson", "100 downtowza", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["Bob Fulfghfgherson", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["Bob Fufghfghlkersonasdassssssssssssssssdsdasddddddddddsasdasdasdasdasasdasdasdasdasdasdasdasdsdasdasdsdsdsdsdsddsdasd", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["912-234-2345912-234-2345912-234-2345", "100 downtfghfgwn avenue", "912-234-2345912-234-2345912-234-2345", "no"]) data.append(["Bob Fufghflkerson", "100 unknown avenue", "912-234-2345912-234-2345912-234-2345", "no"]) blah = print_table(data, testheader,66,4) for each in blah: print each blah = print_table(data, testheader,120,4) for each in blah: print each blah = print_table(data, testheader,40,4) for each in blah: print each print_table_tester()