0

I am working on a file editing script that is able to find a certain section of the file based on some keywords, then replace a section below it with an alternative section. It is important to know that the files are formatted very strictly so variances should be little to none across files.

The files would look something like:

Z1 ; move to next (0)
Q6 ; comment1
X5 Y7 ; point
X6 Y9 ; point
X4 Y8 ; point
Q6 ; comment1
Z2 ; move to next (1)
Q6 ; comment1
X9 Y6 ; point
X4 Y2 ; point
X1 Y7 ; point
Q6 ; comment1

As of right now, my script is able to search the file and perform an action based on the comment after the ;, but I am unsure on how to delete what is there and replace it without iterating through the entire file multiple times.

It would look something like this:

stuff to add:

A1 B4 ; point
A7 B3 ; point
A1 B7 ; point

So the script would search looking for a case of 'Z1', then 'Q6' and if that happens, replace the 'X Y' section with the new 'A B' section. The edited version would then look like:

 Z1 ; move to next (0)
Q6 ; comment1
A1 B4 ; point
A7 B3 ; point
A1 B7 ; point
Q6 ; comment1
Z2 ; move to next (1)
Q6 ; comment1
X9 Y6 ; point
X4 Y2 ; point
X1 Y7 ; point
Q6 ; comment1

My script so far is:

file_name = "/Users/path/to/file"

with open(file_name, 'r+') as f:
z_val = []
    content = f.readlines()

    for line in content:
        coordinate_set = {}
        if ';' in line:
            if 'Z' in line:
                try:
                    coord, comment = line.strip('\n').split(";")
                    for num in coord.split()[1:]:
                        if 'Z' in num:
                            z_val.append(num)
                except:
                    pass

This works well to find the area with the 'Z1' and append the '1' value to a list, however I am unsure on how to make the section edit and replace. Some research into the topics makes me think that I may need to use enumerate and seek to work my way backwards up the section list as I delete each line I don't want, then, once it is at the bottom of the section, write in the new section.

Is there maybe a simpler or more efficient way to do this? Thank you in advance!!!

paperstsoap
  • 335
  • 4
  • 13
  • 1
    You can't edit a file in place. Read everything into a Python list, modify the list, then write it all back out to the file. – Barmar Jan 03 '18 at 17:55
  • @Barmar so then you would just using standard list comprehension functions alike append, pop, etc? – paperstsoap Jan 03 '18 at 17:58
  • Yeah, stuff like that. – Barmar Jan 03 '18 at 17:58
  • To be more specific, you can write anywhere in a file, but you cannot delete lines. – jbch Jan 03 '18 at 17:58
  • @Barmar I am messing around with reading everything in to a list, however I am having trouble getting it to read into the list and maintain the same format. I think I need a list of list so that each line maintains the correct format, but I am not sure how to keep it in that format. – paperstsoap Jan 03 '18 at 18:48
  • Just make a list of `line.strip('\n').split(';')`. That will be a list of lists. – Barmar Jan 03 '18 at 19:52

1 Answers1

0

Here is a restructured version of your code that writes the number after each Z to a new file. If you really need to you could write to the same file after processing it. But it's generally a good idea to write to a new file.

all_z_vals = []
with open(file_name, 'r') as f:
    for line in f.readlines():
        if line[0] == 'Z' and ';' in line:
            z_str, comment = line.split(';')
            z_num = z_str[1:].rstrip()  # rstrip removes right hand side whitespace
            all_z_vals.append(z_num)

with open('my_z_values.txt', 'w') as outfile:
    outfile.writelines(all_z_vals)

Side note: avoid using try-except, it incurs a performance decreases as it prepares to catch exceptions (that in this case can be avoided).

Stefan Collier
  • 4,314
  • 2
  • 23
  • 33
  • The try-except is from a previous version that had a mix of ; and () for the comment, which required the try-except, but that has since been retired. My question for this method is: What if 'Z1' is not at line[0]? The sections are formatted strictly, but may not be exactly the same length. Also my 'Z' values are a trigger for the start/end of a section but the 'X Y' is the part that actually needs to be modified. – paperstsoap Jan 03 '18 at 18:28
  • Just a foreword: `line` is a string. So `line[0]` is a `char`, so 'Z' is the only bit found, not 'Z1'. When the line does not start with a a 'Z' then it ignores the line – Stefan Collier Jan 08 '18 at 17:17
  • Oh! So you are using the `Z` lines to deetermine when to start catching input? Why not just ignore the lines that do not start with `A B` – Stefan Collier Jan 08 '18 at 17:18