How to change specified part of txt file in Python - python

I have txt file like this:
tw004:Galaxy S5:Samsung:Mobilni telefon:5
tw002:Galaxy S6:Samsung:Mobilni telefon:1
tw001:Huawei P8:Huawei:Mobilni telefon:4
tw003:Huawei P9:Huawei:Mobilni telefon:3
(where tw001 to tw004 is code of some devices and last part of a line is amount 5,1,4,3)
Now I'm trying to add amount to devices with specified code:
def add_devices():
device_file = open ('uredjaji.txt','r').readlines()
code = input("Enter device code: ")
for i in device_file:
device = i.strip("\n").split(":")
if code == device[0]:
device_file = open('uredjaji.txt', 'a')
amount = input("How many devices you are adding: ")
device[4] = int(device[4])
device[4] += int(amount)
device_file.writelines(str(device[4]))
device_file.close()
add_devices()
My problem is that sum of specified device is just add to the end of txt file.
How to fix that?
(For example if I enter tw004 and add 3 sum 8 is just aded to tw003:Huawei P9:Huawei:Mobilni telefon:38)

First of all, don't open multiple file handles to the same file - that's a disaster waiting to happen.
Second, and more to the point, you need to remove the previous number before you add a new one - the way you're doing it is essentially just appending the data to the end of the file. You'll have to do a bit of seeking and truncating in order to achieve what you want, something like:
def add_devices():
# no need to keep our files open while users provide their input
code = input("Enter device code: ")
amount = int(input("How many devices you are adding: "))
# you might want to validate the amount before converting to integer, tho
with open("uredjaji.txt", "r+") as f:
current_position = 0 # keep track of our current position in the file
line = f.readline() # we need to do it manually for .tell() to work
while line:
# no need to parse the whole line to check for the code
if line[:len(code) + 1] == code + ":": # code found
remaining_content = f.read() # read the rest of the file first
f.seek(current_position) # seek back to the current line position
f.truncate() # delete the rest of the file, including the current line
line = line.rstrip() # clear out the whitespace at the end
amount_index = line.rfind(":") + 1 # find the amount index position
current_amount = int(line[amount_index:]) # get our amount
# slice out the old amount, replace with the new:
line = line[:amount_index] + str(current_amount + amount) + "\n"
f.write(line) # write it back to the file
f.write(remaining_content) # write the remaining content
return # done!
current_position = f.tell() # cache our current position
line = f.readline() # get the next line
print("Invalid device code: {}".format(code))
add_devices()

Since you are wanting to update the same file, you will have to separate the code into distinct parts, since you shouldn't read and write to a file at the same time. It could be ordered like:
open the file for reading ('r')and read in the devices (you'll end up with a list of devices, or dictionary, or whatever data structure you want to use), and close the file
process the data - this is where you can increase the number of devices and such
open the file for writing ('w'), write the lines, and close the file
You basically have all the code logic already, just need to untangle it so that you can do the 3 suggested steps separately. :)
Edit: extra note - since you split the lines on ':' when reading the file, you will need to do the reverse and ':'.join(device) when writing it back. ;)

Related

Creating words out of numbers from a file

Right so, I have a file with lots of numbers in it. It is a .txt file with binary numbers in it so it has 0's, 1's and spaces every 8 numbers (it is the lyrics to Telegraph Road but in binary, but that isn't important). What I am trying to do is create a program that takes the file, reads a single character of the file, and depending on what it reads it then writes either "one" or "zero" in a second .txt file.
As it stands, as a proof of concept, this works:
with open('binary.txt') as file:
while 1:
string = file.read(1)
if string == "1":
print("one")
elif string == "0":
print("zero")
It prints out either a "one" or "zero" in about 15000 lines:
Picture of the IDLE Shell after running the program
In the future I want it to print them in set of eight (so that one line = one binary ascii code) but this is pointless if I cant get it to do the following first.
The following is instead of printing it to the IDLE, I want to write it into a new .txt file. A few hours of searching, testing and outright guessing has me here:
with open('binary.txt') as file:
with open('words.txt') as paper:
while 1:
string = file.read(1)
if string == "1":
line = ['one']
paper.writelines(line)
elif string == "0":
line = ['zero']
paper.writelines(line)
This then prints to the IDLE:
paper.writelines(line),
io.UnsupportedOperation: not writable
It goes without saying that I'm not very good at this. it has been a long time since I tried programming and I wasn't very good at it then either so any help I will be much appreciative of.
Cheers.
So in python when you use open() function it opens the file in read mode, but you change this by passing a second argument specifying the permissions you need. For your need and to keep things simple you need to open the file in write mode or append mode.
# this will clear all the contents of the file and put the cursor and the beginning
with open('file.txt') as f:
# logic
# this will open the file and put the cursor at the end of file after its contents
with open('file.txt', 'a') as f:
# logic
i think thats what you are trying to do
with open('binary.txt',"r") as file:
with open('words.txt',"r+") as paper:
while 1:
for i in range(8):
string = file.read(1)
if string == "1":
line = 'one '
paper.write(line)
elif string == "0":
line = 'zero '
paper.write(line)
paper.write("\n")
this program will take the binary file items.. and put them in the paper file as you said (1=one and 0=zero. 8 for every line)
Here it is:
with open('binary.txt',"r") as file:
data = file.read()
characters = data.split()
print(len(characters))
file.close()
with open('binary.txt',"r") as file:
with open('words.txt',"w") as paper:
count = 0
while count < len(characters):
for i in range(9):
string = file.read(1)
if string == "1":
line = 'one '
paper.write(line)
print("one")
elif string == "0":
line = 'zero '
paper.write(line)
print("zero")
paper.write("\n")
count += 1
Its probably really inefficient in places but it does the job.
Important stuff:
By not having the written file opened for writing but as default (reading), the program was unable to write to it. Adding "w" solved this, and also added an "r" onto the reading file to be safe.
Opening the read file once before to work out number of lines so that the program would stop churning out returns and making the write file millions of lines long if you didn't stop it immediately.
Worked out the number of lines necessary (the (print(len(characters)) line is, ironically, unnecessary):
data = file.read()
characters = data.split()
print(len(characters))
Limited the number of lines the program could write by first setting a variable to 0, then changed the while loop so that it would continue looping if the variable has a number less than that of how many lines there are and then adding a bit of code to add 1 to the variable after every new line is made:
count = 0
while count < len(characters):
count += 1
for i in range(8) was changed to for i in range(9) so that it would actually produce words in blocks of 8 before making new lines. Before it would make a line of 8 and then a line of 7 every time until the last line, where it would only right the leftover words, which in my case was 6
Read file must have a very specific layout, that is only 0's and 1's, must have a space every 8 numbers and no returns at all:
Picture of the text file, notice how each "line" continues beyond the boundary, this is because each line is 1001 columns long but due to there being a limit per column of 1001, it returns back around to create a new line, while still counting as the same column on the counter at the bottom.

Code to print corresponding CSV/list values for car program is not printing anything at all

I have tried to get help on this question all day, but none of the already-asked questions have solved my problem, and any answers I have asked to help me solve this problem have resulted in answers that didn't answer the question.
As it stands now, my program takes the values of MPG ratings represented in a CSV and puts them in a list. These lists represent maximum and minimum MPGs. Once the max/min MPG rating is found is where I get into my problem. I need to be able to print all the cars that have the minimum/maximum MPG value. Ideally, the models should be printed indented under the print statements for the maximum/minimum mileage ratings.
The way the CSV file is done the MPG ratings are in column 9 (index[8]). The make and models are in columns 2 and 3, respectively (index[1] and index[2], respectively). As you'll see in the code, I tried looping through the list and using an if statement to pull the make/model, but when I do that it does not work. I don't know if the files play a part or not, but any help would be appreciated.
# prints welcome screen, asks user what year they want vehicle data for, and asks user for file name to save vehicle data to
print("Welcome to EPA Mileage Calculator")
yearChoice = int(input("What year would you like to view data for? (2008 or 2009): "))
while yearChoice != 2008 and yearChoice != 2009:
print("Invalid input, please try again")
yearChoice = int(input("What year would you like to view data for? (2008 or 2009): "))
saveResults = input("Enter the filename to save results to: ")
def carData():
if yearChoice == 2008:
fileName = "epaVehicleData2008.csv"
elif yearChoice == 2009:
fileName = "epaVehicleData2009.csv"
fileIn = open(fileName, "r")
fileIn.readline()
minMPG = []
maxMPG = []
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[0] not in ['VANS - PASSENGER TYPE', 'VANS - CARGO TYPE', 'TRUCK', 'MINIVAN - 4WD', 'MINIVAN - 2WD']:
minMPG.append(int(dataList[8]))
maxMPG.append(int(dataList[8]))
maximumMPG = max(maxMPG)
minimumMPG = min(minMPG)
fileOut = open(saveResults, "w")
print("EPA City MPG Calculator", "(" + str(yearChoice) + ")", file=fileOut)
print("---------------------------------", file=fileOut)
print("Maximum Mileage (city):", maximumMPG, file=fileOut)
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[8] == maximumMPG:
print("\t", dataList[1], dataList[2], file=fileOut)
print("Minimum Mileage (city):", minimumMPG, file=fileOut)
for line in fileIn:
line = line.strip()
dataList = line.split(",")
if dataList[8] == minimumMPG:
print("\t", dataList[1], dataList[2], file=fileOut)
fileIn.close()
fileOut.close()
def complete():
print()
print("Operation Success! Mileage data has been saved to", saveResults)
print("Thanks, and have a great day!")
def main():
carData()
complete()
main()
You open the input file only once via:
fileIn = open(fileName, "r")
But then you attempt to iterate over the lines in the file three times using that same file handle. You have three of these:
for line in fileIn:
Since you never close and reopen the file, and you don't do anything to seek back to the beginning of the file, the second and third such iterations will never do anything, because you've already reached the end of the file. Using this construct does not cause the file pointer to be rewound and the contents of the file to be iterated over another time.
Since your interesting print statements are in the second and third iterations over the file, which won't produce any new lines (the code in those iteration blocks will never be called), of course your print statements are never called and no output is generated.
To fix your problem, if this is the only thing wrong with your code, just put this line before each of the second and third iterations over the file:
f.seek(0)
to seek back to the beginning of the file and iterate over the contents a second and third time.
To be more efficient, you could read each line once and store it in a list. Then you could iterate over the list each time, and not have to read from the file three times. You could even do the strip and the split just once, making the code even more efficient.
Another small logic error that I see is that you skip one line in your first iteration over the file. I assume that this is to skip a header row at the start of the file. But you don't do this for the second and third iterations, so it seems that if you only add the seek() as I suggested, you'll be trying to process the header line as a data line. This would also be solved by reading the file once into a list. You'd skip the first line of the file while you do this. If you want to leave the code alone other than adding the seek(), you should also skip the first line before the second and third iterations.

Python Performing calculation on every x line and place it back into original file

I have a list that looks like this
url1
number1
number2
number3
url2
number1
number2
number3
url3
etc
I want to perform calculations on number 2 , and replace it with the new value in the original position of the text file. Here is what i have so far
import itertools
#with open('math.txt', 'r') as f:
# fourthlines = itertools.islice(f, 2, None, 4)
# for line in fourthlines:
# line=float(line)
# #print line
# line=((line-100)/2)
# print line
Issue: this returns the value i want but i want to place it back into math.txt where it came from ( number 2's position )
First writing to another file:
with open("test.txt","r") as rp, open("write.txt","w") as wp:
for line_count, line in enumerate(rp,-2):
if line_count % 4 == 0:
print(line)
#do somethign to line
wp.write('found the line number 2\n')
else:
wp.write(line)
Second, using a temp file modifying the original one, temp files are the safest way of modifying a file:
import tempfile
temp_file = tempfile.NamedTemporaryFile(mode="r+")
with open("test.txt","r") as rp:
for line_count, line in enumerate(rp,-2):
if line_count % 4 == 0:
print(line)
#do somethign to line
line = 'found the line number 2'
temp_file.write(line + '\n')
else:
temp_file.write(line)
temp_file.seek(0) #reset the tempfile's cursor back to the start
with open("test.txt","w") as wp:
for line in temp_file:
wp.write(line)
In either case just change "test.txt" to your text file name, and where I put #do something to line just do whatever you need to do making sure line is a str at the end after doing things to it.
There is a read/write mode for python file objects.
fo = open("foo.txt",'r+')
However, THIS DOES NOT INSERT NEW TEXT INTO A FILE, instead it writes over what is already there. For example.
******original text file*****
hello world!
*****************************
fo = open("foo.txt",'r+')
fo.write('spam')
fo.close()
***********result************
spamo world!
*****************************
I would not use this on a plain text file unless I knew 100% that the data I was writing was the same size as the data that I was replacing. Even then, I would hesitate. If you are set on storing your information as plain text then I think you would be better off writing to a separate file.
On the other hand, if you change your information so it is stored in binary form and the original value and the new value have the same byte size then I think that this would be a good option for you to consider.
My solution will does the calculation and write it at the same time without using temp file.
Solution has two parts :
It will first take the lines from file on which the operation need to be done.
Second, it read file and do the operation on above list of lines and write the new value at the same time i.e. it is going to in place replacement.
Module : fileinput
Using this module you can to do reading and writing to file at the same time.
Check here for more info !!!
Content of math.txt before :
url
1
2
3
url
4
5
6
url
Code:
import fileinput
lines_to_check = []
#First - It will take out the lines on which operation is required
with open("math.txt","r") as fh:
for l_count, line in enumerate(fh,-2):
if l_count % 4 == 0:
lines_to_check.append(line.strip())
#Second - Calculate and write
#As calculation, I am just multiplying value by 100
for line in fileinput.input('math.txt',inplace=1):
if line.strip() in lines_to_check:
line=float(line)
line= line *100
print str(line).strip()
else:
print line.strip()
Content of math.txt after executing code :
url1
1
200.0
3
url2
4
500.0
6
url3
Here is a safe way to do it...which is the approach I'd take as I am a beginner.
Open the file and read its lines into a list (filename.readlines() method).
Lookup the element's index in the list (lines.index(element) method).
Replace the element in the list (list[index]=new_element).
Open the file and [over]write all the lines from you list back into it.
If the file is not extremely long then this method should be sufficient.
I hope this helps you, if not then I am sure it will benefit someone even newer than me. (;

Printing to a file via Python

Hopefully this is an easy fix. I'm trying to edit one field of a file we use for import, however when I run the following code it leaves the file blank and 0kb. Could anyone advise what I'm doing wrong?
import re #import regex so we can use the commands
name = raw_input("Enter filename:") #prompt for file name, press enter to just open test.nhi
if len(name) < 1 : name = "test.nhi"
count = 0
fhand = open(name, 'w+')
for line in fhand:
words = line.split(',') #obtain individual words by using split
words[34] = re.sub(r'\D', "", words[34]) #remove non-numeric chars from string using regex
if len(words[34]) < 1 : continue # If the 34th field is blank go to the next line
elif len(words[34]) == 2 : "{0:0>3}".format([words[34]]) #Add leading zeroes depending on the length of the field
elif len(words[34]) == 3 : "{0:0>2}".format([words[34]])
elif len(words[34]) == 4 : "{0:0>1}".format([words[34]])
fhand.write(words) #write the line
fhand.close() # Close the file after the loop ends
I have taken below text in 'a.txt' as input and modified your code. Please check if it's work for you.
#Intial Content of a.txt
This,program,is,Java,program
This,program,is,12Python,programs
Modified code as follow:
import re
#Reading from file and updating values
fhand = open('a.txt', 'r')
tmp_list=[]
for line in fhand:
#Split line using ','
words = line.split(',')
#Remove non-numeric chars from 34th string using regex
words[3] = re.sub(r'\D', "", words[3])
#Update the 3rd string
# If the 3rd field is blank go to the next line
if len(words[3]) < 1 :
#Removed continue it from here we need to reconstruct the original line and write it to file
print "Field empty.Continue..."
elif len(words[3]) >= 1 and len(words[3]) < 5 :
#format won't add leading zeros. zfill(5) will add required number of leading zeros depending on the length of word[3].
words[3]=words[3].zfill(5)
#After updating 3rd value in words list, again creating a line out of it.
tmp_str = ",".join(words)
tmp_list.append(tmp_str)
fhand.close()
#Writing to same file
whand = open("a.txt",'w')
for val in tmp_list:
whand.write(val)
whand.close()
File content after running code
This,program,is,,program
This,program,is,00012,programs
The file mode 'w+' Truncates your file to 0 bytes, so you'll only be able to read lines that you've written.
Look at Confused by python file mode "w+" for more information.
An idea would be to read the whole file first, close it, and re-open it to write files in it.
Not sure which OS you're on but I think reading and writing to the same file has undefined behaviour.
I guess internally the file object holds the position (try fhand.tell() to see where it is). You could probably adjust it back and forth as you went using fhand.seek(last_read_position) but really that's asking for trouble.
Also, I'm not sure how the script would ever end as it would end up reading the stuff it had just written (in a sort of infinite loop).
Best bet is to read the entire file first:
with open(name, 'r') as f:
lines = f.read().splitlines()
with open(name, 'w') as f:
for l in lines:
# ....
f.write(something)
For 'Printing to a file via Python' you can use:
ifile = open("test.txt","r")
print("Some text...", file = ifile)

getting data out of a txt file

I'm only just beginning my journey into Python. I want to build a little program that will calculate shim sizes for when I do the valve clearances on my motorbike. I will have a file that will have the target clearances, and I will query the user to enter the current shim sizes, and the current clearances. The program will then spit out the target shim size. Looks simple enough, I have built a spread-sheet that does it, but I want to learn python, and this seems like a simple enough project...
Anyway, so far I have this:
def print_target_exhaust(f):
print f.read()
#current_file = open("clearances.txt")
print print_target_exhaust(open("clearances.txt"))
Now, I've got it reading the whole file, but how do I make it ONLY get the value on, for example, line 4. I've tried print f.readline(4) in the function, but that seems to just spit out the first four characters... What am I doing wrong?
I'm brand new, please be easy on me!
-d
To read all the lines:
lines = f.readlines()
Then, to print line 4:
print lines[4]
Note that indices in python start at 0 so that is actually the fifth line in the file.
with open('myfile') as myfile: # Use a with statement so you don't have to remember to close the file
for line_number, data in enumerate(myfile): # Use enumerate to get line numbers starting with 0
if line_number == 3:
print(data)
break # stop looping when you've found the line you want
More information:
with statement
enumerate
Not very efficient, but it should show you how it works. Basically it will keep a running counter on every line it reads. If the line is '4' then it will print it out.
## Open the file with read only permit
f = open("clearances.txt", "r")
counter = 0
## Read the first line
line = f.readline()
## If the file is not empty keep reading line one at a time
## till the file is empty
while line:
counter = counter + 1
if counter == 4
print line
line = f.readline()
f.close()

Categories

Resources