0

I have written this method in order to replace text in line. It prints the correct text as I want it to be replaced but it is not updating those changes in the file. I am quite new to Python, Could you please help me where I am making a mistake?

def regFind(regx, sub_text, file_name):
  c_file = io.StringIO(file_name)
  for line in c_file:
    match = regx.search(line)
    if match:
      replaced_line = re.sub(regx, sub_text, line)
      line = replaced_line
      #print(line)
    yield line

    regx = re.compile(r'^MYTEXT')
    sub_text = 'NewText'
    a_file = open('file.txt').read()
    for line in regFind(regex, sub_text, a_file):
      print(line)
Zeeshan
  • 1,200
  • 12
  • 17

3 Answers3

1

There is a module in the standard library to help edit files "in-place" -- fileinput. Actually, it does not edit files in-place, instead it writes output to a temporary file, and then renames the temporary file to the original file. This makes it appear as though the file has been edited in-place if everything goes well. If there is an exception, or the program is stopped before the renaming step, then the original file remains untouched.

import fileinput
import sys
import re

screen = sys.stdout
def regFind(regx, sub_text, filename):
    for line in fileinput.input([filename],
            inplace=True,
            backup='.bak'   # creates a backup of the original file
            ):
        match = regx.search(line)
        if match:
            line = regx.sub(sub_text, line)
        sys.stdout.write(line)
        yield line

# regex = re.compile(r'foo')    
for line in regFind(regex, sub_text, 'file.txt'):
    screen.write(line+'\n')

fileinput redirects sys.stdout to write to the temporary file, not to the console. So to print to the console, I saved the original sys.stdout to a variable screen and use screen.write instead of print.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • Thank you for your answer unutbu. I have tried this but it destroys all the format of existing file. And writes only the lines back to the file that are being matched. While I want to change only those lines that are matched and rest of lines, I want to be unaffected. – Zeeshan Sep 17 '13 at 13:54
  • Oops, I forgot to call `sys.stdout.write` for each line. That should be fixed now. – unutbu Sep 17 '13 at 13:56
  • Sorry to disaapoint you but i have used sys.stdout.write in my code and it didn't work – Zeeshan Sep 17 '13 at 14:12
  • Its replacing other lines and changing format of file, which I don't want. I only want to replace the lines matched without changing the file format etc – Zeeshan Sep 17 '13 at 14:19
  • if you want I can share more details with you? – Zeeshan Sep 17 '13 at 14:20
  • Can you post the actual code you are running and a sample of the file? – unutbu Sep 17 '13 at 14:24
  • i have added the regex and replacement text variable as well – Zeeshan Sep 17 '13 at 14:47
  • Is there a way to use BufferedStream in Python to do this? – Zeeshan Sep 17 '13 at 14:51
0

You need to write changes to file explicitly. For example, open another file in write mode ('w') and use .write method to put data into disk:

def regFind(regx, sub_text, a_file):
  for line in a_file:
    match = regx.search(line)
    if match:
      replaced_line = re.sub(regx, sub_text, line)
      line = replaced_line
      #print(line)
    yield line

f = open('file.txt')
out = open('result.txt', 'w')
for line in regFind(regex, sub_text, f):
  out.write(line)

(I've also removed unnecessary StringIO and stopped loading the whole file into memory with .read())

P.S. The reason I write to another file is that it's safer. It's possible to change the file in place. But you could loose data if not careful enough.

ash
  • 653
  • 9
  • 20
  • Hi, ash thank you for your answer, I am trying to find out why the above method isn't working. Can you please point it out? – Zeeshan Sep 17 '13 at 12:21
  • Because in order to put something to disk, you need to write data explicitly. For example, by calling .write method. I've also updated the answer. – ash Sep 17 '13 at 12:48
0

Edit Your code does not work because you dont write those lines into text files.

Also if you want to replace text in file you need to copy contents of file, the open the file in writemode(which empties whole file) and then write modified content to file:

def regFindAndReplace(regx, sub_text, fileName):
    textFile = open(fileName)
    fileContent = textFile.readlines()
    textFile.close()
    writeFile = open(fileName,'w')
    for line in fileContent:
        # strip removes newline character if line has one, you probably wont need it but it does not do harm either
        line = line.strip()
        match = regx.search(line)
        if match:
            replaced_line = re.sub(regx, sub_text, line)
            line = replaced_line
            #print(line)
        writeFile.write(line+'\n')
        #'\n' is way to create newline character because stripped line has it no longer
    writeFile.close()

f = 'MyFile.txt'
regFindAndReplace(regex, sub_text, f)
  • Too dangerous. You could loose data if there's an exception between open(fileName, 'w') and writeFile.close(). – ash Sep 17 '13 at 12:44
  • It's possible, but very unlikely something like that is going to happen. Easy fix is what you suggested and another is to create back up automatically with shutil.copyfile(fileName,fileName+'.backUp') and upon no exception delete file with os.remove(fileName+'.backUp') and upon error automatically change back up to it's original form – Henri Korhonen Sep 17 '13 at 12:50
  • I disagree about the "unlikely" part. In fact it's very likely when you write the code and debug it. Of course we can all produce working and non-exception-throwing code on the first attempt, but we still make mistakes sometimes. I agree about the backup suggestion. – ash Sep 17 '13 at 12:54
  • Okay, i never have had that problem, but i'm sorry that i wont edit code to handle exceptions because it would make it more complicated and difficult to follow. I already created exception handling code but chose not to post it due to that reason. :D – Henri Korhonen Sep 17 '13 at 12:58
  • I guess you've never had this problem, because you usually don't change file in place :) – ash Sep 17 '13 at 13:01
  • Well usually yes, but in my last project i wrote lines from internet to file, read and close file. After reopening i wrote modified text to same file and sent it back to internet. After weeks of use with 6 of testers none have had problems with losing data. – Henri Korhonen Sep 17 '13 at 13:05
  • What if the file is bigger and I need to read it line by line? – Zeeshan Sep 17 '13 at 13:09
  • it could be done by file.readline() but then you wouldnt be able to write it at the same time. I cant really imagine why it should be read line by line. – Henri Korhonen Sep 18 '13 at 13:39