Joseph Gagnon
Joseph Gagnon

Reputation: 2135

Python 2.6.6 - How do I print a list in tabular form with aligned columns?

The use case is simple. I have a list of strings of varying lengths and I'd like to print them so that they are displayed in a tabular form (see below). Think of listing a directory on your computer. It displays them as a table that fits the current window size and takes into account the longest value in the list so that all columns are aligned. For my needs I would specify the max row length before it needs to wrap.

config                 constants.py           fuzzer
fuzzer_session         generator.py           README.docx
run_fuzzer_session.py  run_generator.py       tools
util                   VM_Notes.docx          wire_format_discoverer
xml_processor

I came up with a way to do this, but apparently it only works with a newer version of python. The system where it works is using python 3.6.4. I need to do this on a system that's using version 2.6.6. When I tried my code on this system I get the following error:

$ python test.py . 80
Traceback (most recent call last):
  File "test.py", line 46, in <module>
    main()
  File "test.py", line 43, in main
    printTable(dirList, maxLen)
  File "test.py", line 27, in printTable
    printList.append(formatStr.format(item))
ValueError: zero length field name in format

I assume that the technique I'm using to build the format specifier is what it's complaining about.

Here is the logic:

Note: I'm generating my list in this example by just getting a directory listing. My real use case does not use a directory listing.

import os
import sys

def printTable(aList, maxWidth):
    if len(aList) == 0:
        return

    itemMax = 0
    for item in aList:
        if len(item) > itemMax:
            itemMax = len(item)

    if maxWidth > itemMax: 
        numCol = int(maxWidth / itemMax)
    else:
        numCol = 1

    index = 0
    while index < len(aList):
        end = index + numCol
        subList = aList[index:end]
        printList = []

        for item in subList:
            formatStr = '{:%d}' % (itemMax)
            printList.append(formatStr.format(item))

        row = ' '.join(printList)
        print(row)
        index += numCol

def main():
    if len(sys.argv) < 3:
        print("Usage: %s <directory> <max length>" % (sys.argv[0]))
        sys.exit(1)

    aDir = sys.argv[1]
    maxLen = int(sys.argv[2])

    dirList = os.listdir(aDir)
    printTable(dirList, maxLen)

if __name__ == "__main__":
    main()

Is there a way to achieve what I'm trying to do here on python 2.6.6?

I'm sure there are better (more "pythonic") ways to do some of the steps performed here. I do what I know. If anyone wants to suggest better ways, your comments are welcome.

Here are examples of it running successfully:

>python test.py .. 80
config                 constants.py           fuzzer
fuzzer_session         generator.py           README.docx
run_fuzzer_session.py  run_generator.py       tools
util                   VM_Notes.docx          wire_format_discoverer
xml_processor

>python test.py .. 60
config                 constants.py
fuzzer                 fuzzer_session
generator.py           README.docx
run_fuzzer_session.py  run_generator.py
tools                  util
VM_Notes.docx          wire_format_discoverer
xml_processor

>python test.py .. 120
config                 constants.py           fuzzer                 fuzzer_session         generator.py
README.docx            run_fuzzer_session.py  run_generator.py       tools                  util
VM_Notes.docx          wire_format_discoverer xml_processor

Upvotes: 0

Views: 611

Answers (1)

Kevin
Kevin

Reputation: 76254

    for item in subList:
        formatStr = '{:%d}' % (itemMax)
        printList.append(formatStr.format(item))

According to ValueError: zero length field name in format in Python2.6.6, you can't have an "anonymous" format string in 2.6.6. Syntax like "{:10}" didn't become legal until 2.7. Prior to that, you needed to supply an explicit index, like "{0:10}"

    for item in subList:
        formatStr = '{0:%d}' % (itemMax)
        printList.append(formatStr.format(item))

... But I feel like you could save yourself some trouble by skipping all this and using ljust instead.

    for item in subList:
        printList.append(str(item).ljust(itemMax))

Upvotes: 2

Related Questions