# tableFormat.py, by leonardo maffi, V.1.0, Jun 28 2006 def isNumber(x): """isNumber(x): is x a number? (Works with strings too, it doesn't recognize hex numbers).""" if isinstance(x, basestring): x = x.strip() if len(x)>1 and x[-1] == "L": x = x[:-1] if hasattr(x, '__int__'): return True try: float(x) except ValueError: try: complex(x) except ValueError: return False else: return True else: return True def tableFormat(table, sep=" ", format="%g", titles=False): """tableFormat(table, sep=" ", format="%g", titles=False): return a string of table represented with nicely lined up columns. table: list of lists sep: separator between columns. format: format for all numbers; example: "%6.2f". titles: is True if the first row contains the (string) titles of the columns""" # Choose the row used to define the types of the colums (if number or not) if titles and len(table)>1: ref_row = table[1] else: ref_row = table[0] # Find the types of the columns columns_types = [isNumber(el) for el in ref_row] # Choose the justification according to column type justs = [['ljust', 'rjust'][typ] for typ in columns_types] # Find what columns contain floats, ints or longs, to use the given format on them # (So complex numbers don't become formatted too) are_fil = [isinstance(el, (float, int, long)) for el in ref_row] # Create a second table, of all strings, with formatted numbers table2 = [] for nrow, row in enumerate(table): if titles and nrow == 0: # Don't format the title row, if present row2 = map(str, row) else: row2 = [] for el,is_fil in zip(row, are_fil): if is_fil: row2.append(format % el) else: row2.append(str(el)) table2.append(row2) # Find the max widths of all the colums column_widths = map(max, zip(*[map(len, row) for row in table2]) ) # Add the len of the separator to all the columns but the last column_widths = [w+len(sep) for w in column_widths[:-1]] + [column_widths[-1]] # Create the output string (buiding up a list out_lines) out_lines = [] for row in table2: # Create the list of the output line, using rjust or ljust as appropriate, with separators out_line = [getattr(el+sep, ju)(wi) for ju,wi,el in zip(justs, column_widths, row)[:-1]] # Add the last column, without the separators out_line += getattr(row[-1], justs[-1])(column_widths[-1]) # Create the output row, with the given sep between items out_lines.append( "".join(out_line) ) return "\n".join(out_lines) if __name__ == '__main__': print "tableFormat tests" # *********************************** print "Test1:" l = [['short', 'symbol', 'codons', 'name', 'nome'], ['ala', 'a', 'gcu,gcc,gca,gcg', 'alanine', 'alanina'], ['arg', 'r', 'cgu,cgc,cga,cgg,aga,agg', 'arginine', 'arginina']] print tableFormat(l, sep="; ", titles=True), "\n\n" print "Test2:" l = [["first", "second", "third"], ["a", -5, 6J], ["hello", 58, 12e6-2J]] print tableFormat(l, titles=True), "\n\n" print "Test3:" l = [[1.6, 2.33333333333333333, 44]] print tableFormat(l, sep=", ", format="%6.2f") print "isNumber tests" # *********************************** number_tests = 10, 10L, 10.5, 010, 010.0, 10J, -5.1e21-2.1e20j, "10", "10L", "10.5", "010", "010.0", "10J", "-5.1e21-2.1e20j" for x in number_tests: assert isNumber(x)