Python: Why won't my loop iterate? - python

I have a simple bit of python code that opens two files, and loops through each string in one file, looking for the matching string (or part of it) in the other file. If it finds it, it should write that line to file. For some reason it isn't iterating through. Here is my code:
out = open("outputfile.txt", "w")
with open("inputfile1.txt", "r") as f:
with open("inputfle2.txt", "r") as map:
for line in f:
for mline in map:
if line[0:6] in mline:
out.write(line)
For some reason the resultant output file only contains one line. I have checked the line and it is correct, so the code is doing what I want but the loop is not iterating through both files for some reason. I know there's an obvious solution to this but hours of searching and fiddling with my code haven't yielded any results.

By the time that line gets to the second line of file f, mline already read through all the lines of map and exhausted the generator.
You need to cache map's content:
out = open("outputfile.txt", "w")
with open("inputfle2.txt", "r") as map:
map_lines = map.readlines()
with open("inputfile1.txt", "r") as f:
for line in f:
for mline in map_lines:
if line[0:6] in mline:
out.write(line)

Related

Can you delete all the lines of a .txt file after a specific line?

I am trying to delete all the lines in a text file after a line that contains a specific string. What I am trying to do is find the number of the line in said file and rewrite the whole text up until that line.
The code that I'm trying is the following:
import itertools as it
with open('sampletext.txt', "r") as rf:
for num, line in enumerate(rf, 1): #Finds the number of the line in which a specific string is contained
if 'string' in line:
print(num)
with open('sampletext_copy.txt', "w") as wf:
for line in it.islice(rf, 0, num):
wf.write(line)
Also would appreciate any tips on how to do this. Thank you!
You could do it like this:
with open('sampletext.txt', "r") as rf, open('sampletext_copy.txt', "w") as wf:
for line in rf:
if 'string' in line:
break
wf.write(line)
Basically, you open both files at the same time, then read the input file line-by-line. If string is in the line, then you're done - otherwise, write it to the output file.
In case if you want to apply changes to original file, it's possible to do using .truncate() method of file object:
with open(r"sampletext.txt", "r+") as f:
while line := f.readline():
if line.rstrip() == "string": # line.startswith("string")
f.truncate(f.tell()) # removes all content after current position
break
Here we iterating over file until reach this specific line and resize stream to size of bytes we've already read (to get it we use .tell()).
Just to complement Donut's answer, if you want to modify the file in place, there's a much more efficient solution:
with open('sampletext.txt', "r+") as f:
for line in iter(f.readline, ''): # Can't use for line in f: because it disables
# tell for txt
# Or for walrus lovers:
# while line := f.readline():
if 'string' in line:
f.seek(0, 1) # Needed to ensure underlying handle matches logical read
# position; f.seek(f.tell()) is logically equivalent
f.truncate()
break
If issue #26158 is ever fixed (so calling truncate on a file actually truncates at the logical position, not the arbitrary position of the underlying raw handle that's likely advanced a great deal due to buffering), this simpler code would work:
with open('sampletext.txt', "r+") as f:
for line in f:
if 'string' in line:
f.truncate()
break

Python: Write when reading a file

I have a file in which each line contains a sentence. Some sentences are however empty, i.e. in this case there is just "\n" newline character on the line.
What I want to do is: if I find an empty sentence, I want to replace it with some symbol like .
If I replace "\n", it will be replaced at all places in the file.
However, I am not sure how to do this:
import sys
f = open(sys.argv[1], "wr")
for line in f:
if len(line.strip())==0:
line.replace("\n", "empty")
# Then write the line back on the file
f.write(line + "\n") # Will this replace the line in the file?
Is the above code correct? Can I simultaneously read the line and edit it too?
This is a quick way of solving the problem, but not the ideal way of doing it should you have memory constrictions.
f = open(sys.argv[1], "r")
lines = f.readlines()
f.close()
lines = ['empty' if i == '\n' else i for i in lines]
f = open(sys.argv[1], "w")
f.writelines(lines)
f.close()
Should you have memory restrictions, creating a function utilising yield would be the best way to go about this
Edit: I should also say unless there has been an update, I don't believe it is possible to overwrite a specific line in a file using python without re-writing the entire file.

Copying lines into python

I am trying to write a program that copies every other line from thisFile.txt into thatFile.txt, but right now, I'm just having trouble getting the lines from thisFile.txt to copy into thatFile.txt.
I have two different methods that I'm trying to use to copy, one that is commented out and the other that's in a for loop before the commented section.
file_one=open('thisFile.txt','w+')
file_two=open('thatFile.txt','w+')
file_one.write('Hello\nHow\nAre\nYou')
for line in file_one:
file_two.write(line)
#line=' '
#while line !='':
# line=file_one.readline()
# file_two.write(line)
file_one.close()
file_two.close()
You've opened both files for reading and writing, but after writing to the first file are expecting to read from that file immediately. The file pointer is at the end of the file. If you .seek(0) back to the beginning of the file it will work:
file_one=open('thisFile.txt','w+')
file_two=open('thatFile.txt','w+')
file_one.write('Hello\nHow\nAre\nYou')
# rewind the file to prep for read.
file_one.seek(0)
for line in file_one:
file_two.write(line)
file_one.close()
file_two.close()
To address the first question (copying all lines). You need to open the file you want in mode='r' then write to the next file which is open with mode='w' (or simply 'r' and 'w').
with open('test.txt', 'r') as f1:
lines = f1.readlines()
with open('test2.txt', 'w') as f2:
for line in lines:
f2.write(line)
For the first file you take readlines() to actually read every single line.
To address the second issue (every other line):
with open('test.txt', 'r') as f1:
lines = f1.readlines()
with open('test2.txt', 'w') as f2:
for i,line in enumerate(lines):
if i % 2 == 0:
f2.write(line)
else:
pass
You just need to implement enumerate() to loop through the list and provide only the lines whose keys are even. You can change to odd of course.

Script not writing to file

I would like to make it so that it opens up alan.txt, search the text for all instance of scholary_tehologian and if found, add the word "test" under it. when I tried doing it this way:
## Script
with open('alan.txt', 'r+') as f:
for line in f:
if "scholarly_theologian" in line:
f.write("test")
it wouldn't write anything. I'm in Windows 8.1
You can't modify a file like this. You can only append to it, write characters instead of others, or rewrite it entirely. See How do I modify a text file in Python?.
What you should do is create another file with the content you want.
EDIT:
Claudio's answer has the code for what I offered. It has the benefit (over manicphase's code) of not keeping the whole file in memory. This is important if the file is long. manicphase's answer, on the other hand, has the benefit of not creating a second file. It rewrites the original one. Choose the one that fits your needs.
Rewritten answer because the last one was wrong.
If you want to read lines you have to put .readlines() after open(...) or f. Then there's a few ways you could insert "test".
## Script
with open('alan.txt', 'r') as f:
lines = f.readlines()
for i in range(len(lines)):
if "scholarly_theologian" in lines[i]:
lines[i] = lines[i] + "\ntest"
with open('alan.txt', 'w') as f:
f.write("\n".join(lines))
This should do the trick:
with open('output.txt', 'w') as o:
with open('alan.txt', 'r') as f:
for line in f:
o.write(line)
if line.find('scholarly_theoligian'):
o.write('test')
Like Ella Shar mentioned, you need to create a new file and add the new content into it.
If working with two files is not acceptable, the next step would be to delete the input file, and to rename the output file.

How to delete parts of a file in python?

I have a file named a.txt which looks like this:
I'm the first line
I'm the second line.
There may be more lines here.
I'm below an empty line.
I'm a line.
More lines here.
Now, I want to remove the contents above the empty line(including the empty line itself).
How could I do this in a Pythonic way?
Basically you can't delete stuff from the beginning of a file, so you will have to write to a new file.
I think the pythonic way looks like this:
# get a iterator over the lines in the file:
with open("input.txt", 'rt') as lines:
# while the line is not empty drop it
for line in lines:
if not line.strip():
break
# now lines is at the point after the first paragraph
# so write out everything from here
with open("output.txt", 'wt') as out:
out.writelines(lines)
Here are some simpler versions of this, without with for older Python versions:
lines = open("input.txt", 'rt')
for line in lines:
if not line.strip():
break
open("output.txt", 'wt').writelines(lines)
and a very straight forward version that simply splits the file at the empty line:
# first, read everything from the old file
text = open("input.txt", 'rt').read()
# split it at the first empty line ("\n\n")
first, rest = text.split('\n\n',1)
# make a new file and write the rest
open("output.txt", 'wt').write(rest)
Note that this can be pretty fragile, for example windows often uses \r\n as a single linebreak, so a empty line would be \r\n\r\n instead. But often you know the format of the file uses one kind of linebreaks only, so this could be fine.
Naive approach by iterating over the lines in the file one by one top to bottom:
#!/usr/bin/env python
with open("4692065.txt", 'r') as src, open("4692065.cut.txt", "w") as dest:
keep = False
for line in src:
if keep: dest.write(line)
if line.strip() == '': keep = True
The fileinput module (from the standard library) is convenient for this kind of thing. It sets things up so you can act as though your are editing the file "in-place":
import fileinput
import sys
fileobj=iter(fileinput.input(['a.txt'], inplace=True))
# iterate through the file until you find an empty line.
for line in fileobj:
if not line.strip():
break
# Iterators (like `fileobj`) pick up where they left off.
# Starting a new for-loop saves you one `if` statement and boolean variable.
for line in fileobj:
sys.stdout.write(line)
Any idea how big the file is going to be?
You could read the file into memory:
f = open('your_file', 'r')
lines = f.readlines()
which will read the file line by line and store those lines in a list (lines).
Then, close the file and reopen with 'w':
f.close()
f = open('your_file', 'w')
for line in lines:
if your_if_here:
f.write(line)
This will overwrite the current file. Then you can pick and choose which lines from the list you want to write back in. Probably not a very good idea if the file gets to large though, since the entire file has to reside in memory. But, it doesn't require that you create a second file to dump your output.
from itertools import dropwhile, islice
def content_after_emptyline(file_object):
return islice(dropwhile(lambda line: line.strip(), file_object), 1, None)
with open("filename") as f:
for line in content_after_emptyline(f):
print line,
You could do a little something like this:
with open('a.txt', 'r') as file:
lines = file.readlines()
blank_line = lines.index('\n')
lines = lines[blank_line+1:] #\n is the index of the blank line
with open('a.txt', 'w') as file:
file.write('\n'.join(lines))
and that makes the job much simpler.

Categories