2

I want to print some variables to a file in a custom table format and have the ability to add to the table without adding the header again and keeping previous information. Here's my code:

import time as r
data = r.strftime("%d %m %Y %I %M")
with open('myfile.txt','a') as f:
    f.write(data + '\n')

Here's the output in the text file:

01 07 2022 01 19

Now here's the output I want:

_________________________________
|Day |Month |Year |Hour |Minute |
|-------------------------------|
|01  |07    |2022 |01   |19     |
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|

And I want to have the ability that if I run the file again that it would add the new output it would look something like this:

_________________________________
|Day |Month |Year |Hour |Minute |
|-------------------------------|
|01  |07    |2022 |01   |19     |
|===============================|
|01  |07    |2022 |02   |10     |
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|

I know this is an absurd post but does anyone know how? Thanks.

Zen35X
  • 76
  • 2
  • 10
  • it will be simpler to read all data to Python as list of lines, replace last line `|^^^|` in list with new lines (with new data), and write all back to file. – furas Jun 30 '22 at 23:32

4 Answers4

1

Two answers for you...

  1. Use a Library from Pypi designed for printing tables.
  2. Build it yourself using string formatting

I highly recommend the first one because it's easier to use the library than it is to build custom functions for almost the same result. Some I've used in the past and can recommend:

Check out the projects and see if it's something you could use.

For the second option, you can build it yourself by being clever with padding.

Heres a tutorial -> https://www.geeksforgeeks.org/add-padding-to-a-string-in-python/

I say be clever because you'll have to find the string with the longest length if you want things to stay symmetrical.

JaX
  • 111
  • 1
  • 3
1

Using basic string print and string formatting you can get the result.

First, as you well-did, you have to insert the new date in the file:

import time as r
data = r.strftime("%d %m %Y %I %M")
with open('myfile.txt','a') as f:
    f.write(data + '\n')

Then, you have to get all the dates that you have registered in the file:

with open('myfile.txt', 'r') as file:
    data = file.readlines()

data = [string[:-1] for string in data] # To delete the '\n'

Finally, the printing part, with a for loop to get all the elements:

print('_________________________________')
print('|Day |Month |Year |Hour |Minute |')
print('|-------------------------------|')

for elements in data:
    element = elements.split()
    print(f'|{element[0]}  |{element[1]}    |{element[2]} |{element[3]}   | 
            {element[4]}     |')
    if elements != data[-1]:
        print("|===============================|")
    else:
        print("|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|")

NOTE: You can use libraries such as pprint: PPrint description from the Pypi official documentation

Apyre
  • 55
  • 4
  • what to do if I use a string that doesn't have 1 set length sometimes its 3 characters sometimes is 30 would their be a way to adjust the space for it to not be off center? thanks – Zen35X Jul 01 '22 at 00:46
  • Well, i would need an example for that since there is between 00 and 31 days in a month, 00 to 12 months in a year, we are in the 2000 centuries (4 caracters), between 00 and 60 minutes and 00 to 24 hours in a day which are always the same number of caracters. – Apyre Jul 01 '22 at 08:42
  • 1
    But all you have to do is to take the maximum length of the data of each column and add this number of spaces at the beginning. After that you just have to substract each time: `maxLengthElements = [max([len(element[i]) for element in data] for i in range(5)]` Which will get you all the maximum of the lengths of each parameters. Then for the first print: `print(f'|Day{" " * maxLengthsElements[0]} |Month{" " * maxLengthsElements[1]} | etc...')` – Apyre Jul 01 '22 at 08:47
  • 1
    And for the last print (in the for loop) you will get: `print(f'|{element[0]}{" " * (maxLengthElements[0] - len(element[0])} |{element[1]}{" " * (maxLengthElements[1] - len(element[1])} |{element[2]}etc...')` **PS**: Sorry for the code a bit hard to read but stackOverflow has a limit of characters per messages. – Apyre Jul 01 '22 at 08:50
1

You can use the tabulate library.

1

The first call to the fun function will create the header, add the first data and put the end line filled with '^'*31. To ensure, that it is indeed the first call and do not create the header anew at each subsequent call there is the if block.

While the first call opens time.txt in the reading mode 'r', all other calls open it in the 'r+' mode which opens the file both for reading and writing. When the file is read and everything from it is saved to saved (everything, but for the end line), the cursor of the parser is moved the start of the opened file, so that it can be rewritten with the new data with the trailing end line.

def fun():
    import time
    import os.path
    seperator='|'+'-'*31+'|\n'
    end = '|'+'^'*31+'|'
    if not os.path.isfile('time.txt'): #checking if the file exist
        with open('time.txt','w') as f:
            header= '_'*32+'\n'+\
                    '|Day |Month |Year |Hour |Minute |\n'
            t=time.localtime()
            data = (f'|{t[2]:<4}|{t[1]:<6}|{t[0]:<5}'
                    f'|{t[3]:<5}|{t[4]:<7}|\n')
            f.write(header+seperator+data+end)
    else:
        with open('time.txt','r+') as f:
            saved=f.readlines()[:-1] #saving all, but the end line
            f.seek(0) #set the cursor to the start of the file
            t=time.localtime()
            data = (f'|{t[2]:<4}|{t[1]:<6}|{t[0]:<5}'
                    f'|{t[3]:<5}|{t[4]:<7}|\n')
            f.writelines(saved+[seperator,data,end])            

It may not be the ideal option that will meet your needs... And i dare not say that the code is faultlessly.

Note: If the 'time.txt' already exists, but empty or/and without the header then the header won't be created.