Replacing a substring in a text file - python

Gotta write a function that receives a file path and a "new_song" string(aka def my_mp4_playlist(file_path, new_song). The function does 2 things: open the file and write the name of the new song in the 3rd line of the file (in the correct position) and then prints out the new file content.
Starting file content:
Tudo Bom;Static and Ben El Tavori;5:13;
I Gotta Feeling;The Black Eyed Peas;4:05;
Instrumental;Unknown;4:15;
Paradise;Coldplay;4:23;
Where is the love?;The Black Eyed Peas;4:13;
Required print:
Tudo Bom;Static and Ben El Tavori;5:13;
I Gotta Feeling;The Black Eyed Peas;4:05;
**new_song**;Unknown;4:15;
Paradise;Coldplay;4:23;
Where is the love?;The Black Eyed Peas;4:13;
What I have so far:
def my_mp4_playlist(file_path, new_song):
with open(file_path, "r") as reading_file:
data = reading_file.read()
data = data.split("\n")
individual = []
for element in data:
individual.append(element.split(";"))
for song in individual:
song.remove(song[3]) #this removes a space leftover as the last value in each list
individual = individual[3][0].replace(individual[3][0], new_song)
with open(file_path, "w") as writing_file:
writing_file.write(individual)
with open(file_path, "r") as complete_file:
print(complete_file.read())
Unfortunately the replace() method overwrites the entire file content and only new_song appears there. How should I go about this?

This line here is your issue:
individual = individual[3][0].replace(individual[3][0], new_song)
A simple assignment should do the trick:
individual[2][0] = new_song
Please note that I am using index 2 for the 3rd line.
Also, you cannot pass a list as parameter to write(), you can only pass a string.
You can use join() and list comprehension to build your string. Your code would then look like this:
def my_mp4_playlist(file_path, new_song):
with open(file_path, "r") as reading_file:
data = reading_file.read()
data = data.split("\n")
individual = []
for element in data:
individual.append(element.split(";"))
individual[2][0] = new_song
data = "\n".join([";".join(el) for el in individual])
with open(file_path, "w") as writing_file:
writing_file.write(data)
with open(file_path, "r") as complete_file:
print(complete_file.read())

Try this one. I did not know if your replacement is always at the same place or has always the same name so I added another attribute where you have to put the name of the part which has to be replaced
path = "YOUR/PATH/FILE.txt"
old_song= "Instrumental"
new_song = "ABCDEFG"
def my_mp4_playlist(file_path, new_song, old_song):
with open(file_path, "r+") as f:
content = f.read().replace(old_song, new_song)
f.truncate(0)
f.seek(0, 0)
f.write(content)
my_mp4_playlist(path, new_song, old_song)

I will just tell you the mistake in your code.
individual = individual[3][0].replace(individual[3][0], new_song)
You have mentioned it as 3rd element so individual[3][0] should be individual[2][0]
This one replaces individual with new value of individual[2][0].
But you just need to update that line:
individual[2][0] = individual[2][0].replace(individual[2][0], new_song)
which can be further simplified to:
individual[2][0] = new_song

First of all, as somebody said, you don't need to split the data, you can use reading_file.readlines().
Secondly, you said you want to replace the third line, not the forth, but in your code you are doing
individual = individual[3][0].replace(individual[3][0], new_song)
Remember that lists starts with the index 0.
With that being said, here's what I think would work:
def my_mp4_playlist(file_path, new_song):
with open(file_path, "r") as reading_file:
data = reading_file.readlines()
song_to_be_changed = data[2][:data[2].index(";")]
with open(file_path, "w") as writing_file:
writing_file.write("".join(data).replace(song_to_be_changed, new_song))
with open(file_path, "r") as complete_file:
print(complete_file.read())

Related

So I just created a text file and copied text from an already existing file using a with loop. How do I open newly created file in same prog?

I'm making a program that takes text from an input file, then you input a file where it copies the already existing file text. Then, I need to replace a few words there and print the count of how many of these words were replaced. This is my code so far, but since with loops close the newly created file, I have no idea how to open it back again for reading and writing and counting. This is my awful code so far:
filename=input("Sisesta tekstifaili nimi: ")
inputFile=open(filename, "r")
b=input("Sisesta uue tekstifaili nimi: ")
uusFail=open(b+".txt", "w+")
f=uusFail
with inputFile as input:
with uusFail as output:
for line in input:
output.write(line)
lines[]
asendus = {'hello':'tere', 'Hello':'Tere'}
with uusFail as infile
for line in infile
for src, target in asendus
line = line, replace(src, target)
lines.append(line)
with uusFail as outfile:
for line in lines:
outfile.write(line)
There are a lot of unnecessary loops in your code. when you read the file, you can treat it as a whole and count the number of occurrences and replace them. Here is a modified version of your code:
infile = input('Enter file name: ')
outfile = input('enter out file: ')
with open(infile) as f:
content = f.read()
asendus = {'hello':'tere', 'Hello':'Tere'}
my_count = 0
for src, target in asendus.items():
my_count += content.count(src)
content = content.replace(src, target)
with open(f'{outfile}.txt','w+' ) as f:
f.write(content)
You need to reopen the file in the second block of code:
with open(b+".txt", "r") as infile:

how to join incorporate splitted lines with replacing data from a file into the same string

So as most of us are thinking it's a duplicate which is not, so what I'm trying to achieve is let's say there is a Master string like the below and couple of files mentioned in it then we need to open the files and check if there are any other files included in it, if so we need to copy that into the line where we fetched that particular text.
Master String:
Welcome
How are you
file.txt
everything alright
signature.txt
Thanks
file.txt
ABCDEFGHtele.txt
tele.txt
IJKL
signature.txt
SAK
Output:
Welcome
How are you
ABCD
EFGH
IJKL
everything alright
SAK
Thanks
for msplitin [stext.split('\n')]:
for num, items in enumerate(stext,1):
if items.strip().startswith("here is") and items.strip().endswith(".txt"):
gmsf = open(os.path.join(os.getcwd()+"\txt", items[8:]), "r")
gmsfstr = gmsf.read()
newline = items.replace(items, gmsfstr)
How to join these replace items in the same string format.
Also, any idea on how to re-iterate the same function until there are no ".txt". So, once the join is done there might be other ".txt" inside a ".txt.
Thanks for your help in advance.
A recursive approach that works with any level of file name nesting:
from os import linesep
def get_text_from_file(file_path):
with open(file_path) as f:
text = f.read()
return SAK_replace(text)
def SAK_replace(s):
lines = s.splitlines()
for index, l in enumerate(lines):
if l.endswith('.txt'):
lines[index] = get_text_from_file(l)
return linesep.join(lines)
You can try:
s = """Welcome
How are you
here is file.txt
everything alright
here is signature.txt
Thanks"""
data = s.split("\n")
match = ['.txt']
all_matches = [s for s in data if any(xs in s for xs in match)]
for index, item in enumerate(data):
if item in all_matches:
data[index] ="XYZ"
data = "\n".join(data)
print data
Output:
Welcome
How are you
XYZ
everything alright
XYZ
Thanks
Added new requirement:
def file_obj(filename):
fo = open(filename,"r")
s = fo.readlines()
data = s.split("\n")
match = ['.txt']
all_matches = [s for s in data if any(xs in s for xs in match)]
for index, item in enumerate(data):
if item in all_matches:
file_obj(item)
data[index] ="XYZ"
data = "\n".join(data)
print data
file_obj("first_filename")
We can create temporary file object and keep the replaced line in that temporary file object and once everything line is processed then we can replace with the new content to original file. This temporary file will be deleted automatically once its come out from the 'with' statement.
import tempfile
import re
file_pattern = re.compile(ur'(((\w+)\.txt))')
original_content_file_name = 'sample.txt'
"""
sample.txt should have this content.
Welcome
How are you
here is file.txt
everything alright
here is signature.txt
Thanks
"""
replaced_file_str = None
def replace_file_content():
"""
replace the file content using temporary file object.
"""
def read_content(file_name):
# matched file name is read and returned back for replacing.
content = ""
with open(file_name) as fileObj:
content = fileObj.read()
return content
# read the file and keep the replaced text in temporary file object(tempfile object will be deleted automatically).
with open(original_content_file_name, 'r') as file_obj, tempfile.NamedTemporaryFile() as tmp_file:
for line in file_obj.readlines():
if line.strip().startswith("here is") and line.strip().endswith(".txt"):
file_path = re.search(file_pattern, line).group()
line = read_content(file_path) + '\n'
tmp_file.write(line)
tmp_file.seek(0)
# assign the replaced value to this variable
replaced_file_str = tmp_file.read()
# replace with new content to the original file
with open(original_content_file_name, 'w+') as file_obj:
file_obj.write(replaced_file_str)
replace_file_content()

How to add a value to a specific line in a file in python?

I've seen really complex answers on this website as how to edit a specific line on a file but I was wondering if there was a simple way to do it?
I want to search for a name in a file, and on the line that I find that name on, I want to add an integer to the end of the line (as it is a score for a quiz). Or could you tell me how I can replace the entirety of the line with new data?
I have tried a lot of coding but either no change is made, or all of the data in the file gets deleted.
I tried this....
with open ('File.py', 'r') as class_file:
for number, line in enumerate(class_file):
if name in line:
s=open('File.py', 'r').readlines()
s[number]=str(data)
class_file=open('File.py', 'w')
class_file.writelines(new_score)
class_file.close()
As well as this function....
def replace (file, line_number, add_score):
s=open(file, 'w')
new_data=line[line_number].replace(line, add_score)
s.write(str(new_data))
s.close()
As well as this...
def replace_score(file_name, line_num, text):
new = open(file_name, 'r').readlines()
new[line_num] = text
adding_score= open(file_name, 'w')
adding_score.writelines(new)
adding_score.close()
But I still can't get it to work.
The last code works if I'm trying to replace the first line, but not the others.
You need to get the content of the file. Close the file. Modify the content and rewrite the file with the modified content. Try the following:
def replace_score(file_name, line_num, text):
f = open(file_name, 'r')
contents = f.readlines()
f.close()
contents[line_num] = text+"\n"
f = open(file_name, "w")
contents = "".join(contents)
f.write(contents)
f.close()
replace_score("file_path", 10, "replacing_text")
This is Tim Osadchiy's code:
def replace_score(file_name, line_num, text):
f = open(file_name, 'r')
contents = f.readlines()
f.close()
contents[line_num] = text+"\n"
f = open(file_name, "w")
contents = "".join(contents)
f.write(contents)
f.close()
replace_score("file_path", 10, "replacing_text")
This code does work but just remember that the line_num will always be one above the actual line number (as it is an index). So if you wanted line 9 then enter 8, not 9. Also, do not forget to put .txt at the end of the file path (I would've commented but do not have a high enough reputation)

Python search a file for text using input from another file

I'm new to python and programming. I need some help with a python script. There are two files each containing email addresses (more than 5000 lines). Input file contains email addresses that I want to search in the data file(also contains email addresses). Then I want to print the output to a file or display on the console. I search for scripts and was able to modify but I'm not getting the desired results. Can you please help me?
dfile1 (50K lines)
yyy#aaa.com
xxx#aaa.com
zzz#aaa.com
ifile1 (10K lines)
ccc#aaa.com
vvv#aaa.com
xxx#aaa.com
zzz#aaa.com
Output file
xxx#aaa.com
zzz#aaa.com
datafile = 'C:\\Python27\\scripts\\dfile1.txt'
inputfile = 'C:\\Python27\\scripts\\ifile1.txt'
with open(inputfile, 'r') as f:
names = f.readlines()
outputlist = []
with open(datafile, 'r') as fd:
for line in fd:
name = fd.readline()
if name[1:-1] in names:
outputlist.append(line)
else:
print "Nothing found"
print outputlist
New Code
with open(inputfile, 'r') as f:
names = f.readlines()
outputlist = []
with open(datafile, 'r') as f:
for line in f:
name = f.readlines()
if name in names:
outputlist.append(line)
else:
print "Nothing found"
print outputlist
Maybe I'm missing something, but why not use a pair of sets?
#!/usr/local/cpython-3.3/bin/python
data_filename = 'dfile1.txt'
input_filename = 'ifile1.txt'
with open(input_filename, 'r') as input_file:
input_addresses = set(email_address.rstrip() for email_address in input_file.readlines())
with open(data_filename, 'r') as data_file:
data_addresses = set(email_address.rstrip() for email_address in data_file.readlines())
print(input_addresses.intersection(data_addresses))
mitan8 gives the problem you have, but this is what I would do instead:
with open(inputfile, "r") as f:
names = set(i.strip() for i in f)
output = []
with open(datafile, "r") as f:
for name in f:
if name.strip() in names:
print name
This avoids reading the larger datafile into memory.
If you want to write to an output file, you could do this for the second with statement:
with open(datafile, "r") as i, open(outputfile, "w") as o:
for name in i:
if name.strip() in names:
o.write(name)
Here's what I would do:
names=[]
outputList=[]
with open(inputfile) as f:
for line in f:
names.append(line.rstrip("\n")
myEmails=set(names)
with open(outputfile) as fd, open("emails.txt", "w") as output:
for line in fd:
for name in names:
c=line.rstrip("\n")
if name in myEmails:
print name #for console
output.write(name) #for writing to file
I think your issue stems from the following:
name = fd.readline()
if name[1:-1] in names:
name[1:-1] slices each email address so that you skip the first and last characters. While it might be good in general to skip the last character (a newline '\n'), when you load the name database in the "dfile"
with open(inputfile, 'r') as f:
names = f.readlines()
you are including newlines. So, don't slice the names in the "ifile" at all, i.e.
if name in names:
I think you can remove name = fd.readline() since you've already got the line in the for loop. It'll read another line in addition to the for loop, which reads one line every time. Also, I think name[1:-1] should be name, since you don't want to strip the first and last character when searching. with automatically closes the files opened.
PS: How I'd do it:
with open("dfile1") as dfile, open("ifile") as ifile:
lines = "\n".join(set(dfile.read().splitlines()) & set(ifile.read().splitlines())
print(lines)
with open("ofile", "w") as ofile:
ofile.write(lines)
In the above solution, basically I'm taking the union (elements part of both sets) of the lines of both the files to find the common lines.

Match the last word and delete the entire line

Input.txt File
12626232 : Bookmarks
1321121:
126262
Here 126262: can be anything text or digit, so basically will search for last word is : (colon) and delete the entire line
Output.txt File
12626232 : Bookmarks
My Code:
def function_example():
fn = 'input.txt'
f = open(fn)
output = []
for line in f:
if not ":" in line:
output.append(line)
f.close()
f = open(fn, 'w')
f.writelines(output)
f.close()
Problem: When I match with : it remove the entire line, but I just want to check if it is exist in the end of line and if it is end of the line then only remove the entire line.
Any suggestion will be appreciated. Thanks.
I saw as following but not sure how to use it in here
a = "abc here we go:"
print a[:-1]
I believe with this you should be able to achieve what you want.
with open(fname) as f:
lines = f.readlines()
for line in lines:
if not line.strip().endswith(':'):
print line
Here fname is the variable pointing to the file location.
You were almost there with your function. You were checking if : appears anywhere in the line, when you need to check if the line ends with it:
def function_example():
fn = 'input.txt'
f = open(fn)
output = []
for line in f:
if not line.strip().endswith(":"): # This is what you were missing
output.append(line)
f.close()
f = open(fn, 'w')
f.writelines(output)
f.close()
You could have also done if not line.strip()[:-1] == ':':, but endswith() is better suited for your use case.
Here is a compact way to do what you are doing above:
def function_example(infile, outfile, limiter=':'):
''' Filters all lines in :infile: that end in :limiter:
and writes the remaining lines to :outfile: '''
with open(infile) as in, open(outfile,'w') as out:
for line in in:
if not line.strip().endswith(limiter):
out.write(line)
The with statement creates a context and automatically closes files when the block ends.
To search if the last letter is : Do following
if line.strip().endswith(':'):
...Do Something...
You can use a regular expression
import re
#Something end with ':'
regex = re.compile('.(:+)')
new_lines = []
file_name = "path_to_file"
with open(file_name) as _file:
lines = _file.readlines()
new_lines = [line for line in lines if regex.search(line.strip())]
with open(file_name, "w") as _file:
_file.writelines(new_lines)

Categories

Resources