quietgrit quietgrit - 14 days ago 4
Python Question

How to find and replace line only once when found multiple times in Python

I have three lists: filePath, textToFind, textToReplace. I need to open each file at the given filePath, find a line and replace a line. The lists are always in order and always the same length. Here the code:

for i, path in enumerate(filePath):
for line in fileinput.input(path, inplace=1):
sys.stdout.write(line.replace(textToFind[i], textToReplace[i]))


The problem is that textToFind can be found numerous times in the file and so this code replaces all occurrences of the text it finds with the current index position of textToReplace. I need it to break when it finds the item the first time and then move on to the next iteration. How can I do this?

Answer

You need to detect when there's something to replace. If found, flag, but continue writing the rest of the lines or you'll truncate the file.

(note that using zip on the 3 lists avoids carrying the index)

for path,find,replace in zip(filePath,textToFind,textToReplace):    
   match_found = False
   for line in fileinput.input(path, inplace=1):
      if match_found:
         # keep writing the rest of lines, unchanged
         sys.stdout.write(line)
      else:
         # try to replace
         rep = line.replace(find, replace)
         sys.stdout.write(rep)
         if line!=rep:
             # flag: don't replace anything till the end
             match_found = True

EDIT: after a small discussion with the author of another answer, I think his 2 loops pattern is better than 1 with a flag, so I borrowed it, saves the need for the flag, must be slightly faster:

for path,find,replace in zip(filePath,textToFind,textToReplace):
   handle = fileinput.input(path, inplace=1)
   for line in handle:
     rep = line.replace(find, replace)
     sys.stdout.write(rep)
     if line!=rep:
        break
   for line in handle:
      sys.stdout.write(line)
Comments