1

I'm trying to display a bunch of lines from a text file as a table. The text file looks something like this:

capital|What is the capital of Egypt?|Cairo|3
pi|What is pi to two digits?|3.14|3
dozen|How many eggs in a dozen?|12|1
president|Who was the first president?|Washington|1

I'd like to have my code spit out a formatted output that would look something like this:

capital      What is the capital of Egypt?   Cairo        3
pi           What is pi to two digits?       3.14         3
dozen        How many eggs in a dozen?       12           1
president    Who was the first president?    Washington   1

Here's the code I've come up with, but the output is nowhere near looking like the way I want it to.

f = open('quest_load.txt', 'r')
contents = f.read()
contents1 = contents.replace('|','     ')
print(contents1)
f.close()
martineau
  • 119,623
  • 25
  • 170
  • 301
bandit97
  • 13
  • 3
  • Try something like `contents1 = contents.replace('|','\t\t\t')`. That is the tab separator; applying the same spacer to strings of different lengths will still cause them all to be misaligned by the same number of characters – roganjosh Apr 05 '19 at 21:40
  • 1
    Possible duplicate of [Python print string alignment](https://stackoverflow.com/questions/53802256/python-print-string-alignment) – andreihondrari Apr 05 '19 at 21:40
  • @andreihondrari that won't work because you're deliberately cutting to the first 5 chars – roganjosh Apr 05 '19 at 21:41
  • @roganjosh dynamic formatting perhaps? – andreihondrari Apr 05 '19 at 21:42
  • That said, neither will my first approach. I just did exactly what I suggested not to do :/ – roganjosh Apr 05 '19 at 21:42
  • Possible duplicate of [Printing Lists as Tabular Data](https://stackoverflow.com/questions/9535954/printing-lists-as-tabular-data) – roganjosh Apr 05 '19 at 21:47
  • @andreihondrari posted a different dupe which should be closer, I think. – roganjosh Apr 05 '19 at 21:48
  • 1
    Part of the problem with inserting tab characters is that the approach won't work if some of the strings in the same fields are largely differing lengths. If you're writing your output to HTML, you could put this into an HTML table, which corrects for stuff like that. If just to screen, you could put your lines into a list of dicts, calculating the longest length in each field, then run through the dict and print each row, padding each field with space characters. – Ben Apr 05 '19 at 21:50

2 Answers2

1

Loop through the data once, to discover the maximum width of each column:

with open('quest_load.txt', 'r') as f:
    for i, line in enumerate(f):
        if i == 0:
            max_widths = [len(col) for col in line.split('|')]
            continue
        max_widths = [
            max(len(col), curr_max)
            for col, curr_max in zip(line.split('|'), max_widths)
        ]

Then loop again to print the columns, formatting each column according to max width:

with open('quest_load.txt', 'r') as f:
    for line in f:
        content = line.split('|')
        formatted = [
            f'{substr: <{width}}'
            for substr, width in zip(content, max_widths)
        ]
        print('\t'.join(formatted), end='')

Output:

capital     What is the capital of Egypt?   Cairo       3
pi          What is pi to two digits?       3.14        3
dozen       How many eggs in a dozen?       12          1
president   Who was the first president?    Washington  1
PMende
  • 5,171
  • 2
  • 19
  • 26
0

Assuming sl1 represents the lines in the file:

import sys

from collections import defaultdict

sl1 = [
    "capital|What is the capital of Egypt?|Cairo|3",
    "pi|What is pi to two digits?|3.14|3",
    "dozen|How many eggs in a dozen?|12|1",
    "president|Who was the first president?|Washington|1"
]
if not sl1:
    sys.exit(1)

# get the widths of the columns and the rows themselves
rows = []
col_lengths = defaultdict(list)

firs_row = sl1[0].split("|")
col_count = len(firs_row)

for s in sl1:
    col_vals = s.split("|")
    rows.append(col_vals)
    [col_lengths[i].append(len(col_val)) for i, col_val in enumerate(col_vals)]

# find the maximum for each column
for k, vals in col_lengths.items():
    col_lengths[k] = max(vals) + 5  # 5 is a bit of extra spacing

# create a dynamic format based on the widths of the columns
table_format = "{{:{}}}" * col_count
table_format = table_format.format(*col_lengths.values())

# at last print the rows
for row in rows:
    print(table_format.format(*row))

the result will be:

capital       What is the capital of Egypt?     Cairo          3     
pi            What is pi to two digits?         3.14           3     
dozen         How many eggs in a dozen?         12             1     
president     Who was the first president?      Washington     1
andreihondrari
  • 5,743
  • 5
  • 30
  • 59