1

I have text that is key-value pairs separated by '='. I would like to replace the line if the key matches. if not, i would like to append it at the bottom. I've tried several ways, including:

def split_command_key_and_value(command):
   if '=' in command:
      command2 = command.split('=')
      return command2

def test(command, path):
   command2 = split_command_key_and_value(command)
   pattern = command2[0]
   myfile = open(path,'r')  # open file handle for read
# use r'', you don't need to replace '\' with '/'
   result = open(path, 'w')  # open file handle for write
   for line in myfile:
      line = line.strip()  # it's always a good behave to strip what you read from files
      if pattern in line:
         line = command  # if match, replace line
      result.write(line)  # write every line
   myfile.close()  # don't forget to close file handle
   result.close()

I know the above is just to replace text, but it deletes the text in the file, and I can't see why. Could someone point me in the right direction?

Thanks

Update:

I'm almost there, but some of my lines have similar keys, so mutiple lines are matching when only 1 should. I've tried to incorporate a regex boundary in my loop with no luck. My code is below. Does anyone have a suggestion?

There is some text in the file that isn't key-value, so I would like to skip that.

   def modify(self, name, value):
      comb = name + ' ' + '=' + ' ' + value + '\n'
      with open('/file/', 'w') as tmpstream:
         with open('/file/', 'r') as stream:
            for line in stream:
               if setting_name in line:
                  tmpstream.write(comb)
               else:
                  tmpstream.write(line)

I think I got it. See code below.

   def modify(self, name, value):
      comb = name + ' ' + '=' + ' ' + value + '\n'
      mylist = []
      with open('/file/', 'w') as tmpstream:
         with open('/file/', 'r') as stream:
            for line in stream:
               a = line.split()
               b = re.compile('\\b'+name+'\\b')
               if len(a) > 0:
                  if b.search(a[0]):
                     tmpstream.write(comb)
                  else:
                     tmpstream.write(line)

I spoke too soon. It stops at the key-value I provide. So, it only writes one line, and doesn't write the lines that don't match.

def modify(name, value):
   comb = name + ' ' + '=' + ' ' + value + '\n'
   mylist = []
   with open('/file1', 'w') as tmpstream:
      with open('/file2', 'r') as stream:
         for line in stream:
            a = line.split()
            b = re.compile('\\b'+name+'\\b')
            if len(a) > 0:
               if b.search(a[0]):
                  tmpstream.write(comb)
            else:
              tmpstream.write(line)

Can anyone see the issue?

SO03112
  • 178
  • 2
  • 12

3 Answers3

1

Because when you open file for writing

result = open(path, 'w')  # open file handle for write

you just erase it content. Try to write in different file and after all work done replace old file with new one. Or read all data into memory and then process it and write to file.

with open(path) as f:
   data = f.read()
with open(path, 'w') as f:
   for l in data:
       # make job here
kvorobiev
  • 5,012
  • 4
  • 29
  • 35
1

first of all you are reading an writing the same file ... you could first read it all and the write line by line

with open(path,'r') as f:
   myfile = f.read() # read everything in the variable "myfile" 
result = open(path, 'w')  # open file handle for write
for line in myfile.splitlines(): # process the original file content 1 line at a time 
   # as before
Lohmar ASHAR
  • 1,639
  • 14
  • 18
1

I strongly recommend reading python's documentation on how to read and write files.

If you open an existing file in write-mode open(path, 'w'), its content will be erased:

mode can be (...) 'w' for only writing (an existing file with the same name will be erased)

To replace a line in python you can have a look at this: Search and replace a line in a file in Python

Here is one the solutions provided there adapted to your context (tested for python3):

from tempfile import mkstemp
from shutil import move
from os import close

def test(filepath, command):
    # Split command into key/value
    key, _ = command.split('=')
    matched_key = False

    # Create a temporary file
    fh, tmp_absolute_path = mkstemp()

    with open(tmp_absolute_path, 'w') as tmp_stream:
        with open(filepath, 'r') as stream:
            for line in stream:
                if key in line:
                    matched_key = True
                    tmp_stream.write(command + '\n')
                else:
                    tmp_stream.write(line)

        if not matched_key:
            tmp_stream.write(command + '\n')

    close(fh)
    move(tmp_absolute_path, filepath)

Note that with the code above every line that matches key (key=blob or blob=key) will be replaced.

Community
  • 1
  • 1
silel
  • 567
  • 2
  • 10