4

I am working on a problem that says to make a program that gets a user input for a file and then within the file removes a string that the user specifies. I'm not sure how to go from what I have(below) to what the question asks for. As always any and all help is greatly appreciated.

def main():
    outfile = open(input("Enter a file name: "), "a")
    string = input("Enter the string to be removed: ")
    for string in outfile.readlines():
        string = string.replace(string, "")
    outfile.close()
    print("Done")

main()

I took one of the suggestions and tried to get it to work but as I said in my comment below the code below does not return an error it creates an empty file. What am I missing to get the new file to be the old file with the string removed?

def main():
    inpath = input("Enter an input file: ")
    line = input("Enter what you want to remove: ")
    outpath = input("Enter an output file: ")
    with open(inpath, "r") as infile, open(outpath, "w") as outfile:
        for line in infile:
            outfile.write(line.replace(line, "") + "\n")
    print("Done.")

main()
John Joseph
  • 189
  • 2
  • 3
  • 14
  • 6
    you have to open the file on read mode. Try `"a+"` – JBernardo Nov 13 '12 at 23:07
  • As a side note, you have too many variables named `string`. you probably want `string1 = input(...)` and then `string = string.replace(string1,"")`. Finally, you actually need to write the string back into a file. It's a bit difficult to replace strings in a file in place. Usually, you create a new file with the modified contents and then at the end of the day, you move the new file on top of the old file. – mgilson Nov 13 '12 at 23:17
  • @JBernardo: That's true, but it isn't really going to help in this case. You can't just write to the file in the middle of iterating over reading it—or, rather, you can, but it'll do unhappy things, and different unhappy things on different platforms. Still, it is a starting point—and it is the direct explanation of the error the OP's title mentions. – abarnert Nov 13 '12 at 23:39
  • @user60561 my question is older, therefore the thread you mentioned would be the duplicate. – John Joseph Aug 31 '18 at 20:43

1 Answers1

9

A few side notes before getting into the details: When you call string.replace(string, ""), you're telling the string to replace its entire self with the empty string—you might as well just do string = "". Presumably the first string is the search string to replace, so give it a different name, and then use it as, e.g., string.replace(searchString, ""). Also, you don't want to name a variable string, because it's the name of a standard library module. You're calling your input file "outfile", which is apt to be confusing. You probably want to use a with statement instead of an explicit close. Finally, you can iterate the lines in a file with just for line in f:; you don't need for line in f.readlines() (and, if you ever need to deal with Python 2.x, you'll be much happier avoiding readlines(), because it will read the entire file into memory, and then make a huge list of lines in memory).

The first problem, as JBernardo pointed out, is that you've opened the file in "a" mode, which means "write-only, appending to the end". You can use "a+" or "r+" if you want to read and write.

However, that won't really help you. After all, you can't write to the file in the middle of reading it.

There are a few common ways around this.

First, just write to standard output, and let the user do whatever he wants with the results—e.g., redirect it to a file. (In that case, you have print your prompt, "Done" message, etc. to standard error instead, so they don't get redirected to the file.) This is what many Unix tools like sed or sort do, so it's appropriate if you're building a Unix-style tool, but may not be right for other purposes.

def stderrinput(prompt):
    sys.stderr.write(prompt)
    sys.stderr.flush()
    return input()

def main():
    with open(stderrinput("Enter a file name: "), "r") as infile:
        searchString = stderrinput("Enter the string to be removed: ")
        for line in infile:
            print(infile.replace(searchString, ""))
    sys.stderr.write("Done\n")

Second, write to another file. Open the input file in "r" mode, and the output file in "w", mode, and then you're just copying lines:

def main():
    inpath = input("Enter an input file: ")
    outpath = input("Enter an output file: ")
    with open(inpath, "r") as infile, open("outpath", "w") as outfile:
        for line in infile:
            outfile.write(line.replace(searchString, "") + "\n")

Third, read and process the whole file in memory, then truncate and rewrite the whole file:

def main():
    path = input("Enter an input/output file: ")
    with open(path, "r+") as inoutfile:
        lines = [line.replace(searchString, "") for line in inoutfile]
        inoutfile.seek(0)
        inoutfile.truncate()
        inoutfile.writelines(lines)

Finally, write to a temporary file (as with the second option), then move that temporary file on top of the original input file. Something like this:

def main():
    path = input("Enter an input/output file: ")
    with open(path, "r") as infile, tempfile.NamedTemporaryFile("w", delete=False) as outfile:
        for line in infile:
            outfile.write(line.replace(searchString, ""))
        shutil.move(outfile.name, pathname)

This last one is a little tricky, because of the differences between POSIX and Windows. However, it has some big advantages. (For example, if your program gets killed in the middle of operation, no matter how it happens, you're guaranteed to have either the original file or the new file, not some half-written mess.)

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • you should comment that `string = string.replace(string,"")` is nonsense in this loop. At the second line, you're replacement string is the first line. – mgilson Nov 13 '12 at 23:18
  • It's even worse. At the second line, your replacement string is the second line. At every line, your replacement string is the current line. – abarnert Nov 13 '12 at 23:28
  • Actually, come to think of it, given that the first line is guaranteed to be `""`, _both_ statements turn out to be true… – abarnert Nov 13 '12 at 23:40
  • I see what is wrong with what I have, the problem is what you have for possible solutions I don't get what I'm supposed to do with them. will one be enough or is it necessary to combine multiple one in order to get the desired result or am I just over-complicating what I need to do for the program. – John Joseph Nov 14 '12 at 02:04
  • 1
    @JohnDziendziel: You just need one of the four. But you have to decide _which_ of the four you want, which means you have to understand how they're different, and also to understand what you're trying to accomplish. – abarnert Nov 14 '12 at 02:20
  • I was able to get the program to run(no errors), the problem is nothing happens my original file stays the same(nothing removed) and there is no new file that has the old file content minus the removed string. – John Joseph Nov 14 '12 at 02:46