Change value if previous and next value match the given value
line_list = ["a", "b", "c", "d", "e", "f"]
search_list = [
{
"search": "e",
"prev_line": "d",
"next_line": "f",
"replace": "EE"
},
{
"search": "f",
"prev_line": "e",
"next_line": "",
"replace": "FF"
}
]
Since this code will replace e
to EE
, so the prev_line
of f
is no longer be e
. I want it be e
so I can replace f
to FF
. How to fix this?
for search_item in search_list:
search_text = search_item.get("search")
search_text_prev_line = search_item.get("prev_line")
search_text_next_line = search_item.get("next_line")
replace = search_item.get("replace")
for i, line in enumerate(line_list):
prev_line = line_list[i - 1] if i - 1 >= 0 else ""
next_line = line_list[i + 1] if i + 1 < len(line_list) else ""
if line == search_text and prev_line == search_text_prev_line and next_line == search_text_next_line:
line_list[i] = replace
print(line_list) # ['a', 'b', 'c', 'd', 'EE', 'f']
Expected result:
['a', 'b', 'c', 'd', 'EE', 'FF']
You are sequentially updating the list, so that a replacement has effect on subsequent pattern matchings. Instead, you might want to apply replacements in a more simultaneous sense.
line_list = ["a", "b", "c", "d", "e", "f"]
search_list = [
{
"search": "e",
"prev_line": "d",
"next_line": "f",
"replace": "EE"
},
{
"search": "f",
"prev_line": "e",
"next_line": "",
"replace": "FF"
}
]
def replace(search_list, lines):
for pat in search_list:
if (pat['search'], pat['prev_line'], pat['next_line']) == lines:
return pat['replace']
return lines[0]
output = [replace(search_list, lines) for lines
in zip(line_list, ['', *line_list[:-1]], [*line_list[1:], ''])]
print(output) # ['a', 'b', 'c', 'd', 'EE', 'FF']
Here, the second parameter of replace
is a 3-tuple of lines; current line, previous line, and next line. Its role is rather obvious.
We are using list comprehension to apply replace
to each "line". Here, zip
generates the aforementioned 3-tuples.
A simple solution would be to search one list, and modify a copy of it.
LINE_LIST_MASTER = ["a", "b", "c", "d", "e", "f"]
line_list = LINE_LIST_MASTER[:] # make a copy
for search_item in search_list:
search_text = search_item.get("search")
search_text_prev_line = search_item.get("prev_line")
search_text_next_line = search_item.get("next_line")
replace = search_item.get("replace")
for i, line in enumerate(LINE_LIST_MASTER): # search MASTER
prev_line = LINE_LIST_MASTER[i - 1] if i - 1 >= 0 else ""
next_line = LINE_LIST_MASTER[i + 1] if i + 1 < len(LINE_LIST_MASTER) else ""
if line == search_text and prev_line == search_text_prev_line and next_line == search_text_next_line:
line_list[i] = replace # modify work list
Here is one way you can accomplish it. I avoid the issue by making a new list to which we apply the changes, so that we still have the original list to make comparisons to:
line_list = ["a", "b", "c", "d", "e", "f"]
final_list = line_list.copy()
search_list = [
{
"search": "e",
"prev_line": "d",
"next_line": "f",
"replace": "EE"
},
{
"search": "f",
"prev_line": "e",
"next_line": "",
"replace": "FF"
}
]
for search_item in search_list:
try:
for i in range(1, len(line_list)):
if line_list[i-1] == search_item["prev_line"] and line_list[i+1] == search_item["next_line"]\
and line_list[i] == search_item['search']:
final_list[i] = search_item["replace"]
except IndexError:
if search_item["next_line"] == "" and i == len(line_list)-1 and line_list[i] == search_item["search"]\
and search_item["prev_line"]== line_list[i-1]:
final_list[i] = search_item["replace"]
print(final_list)
Edit: Put in a condition that I forgot at the end (checking previous).
Output:
['a', 'b', 'c', 'd', 'EE', 'FF']
If you have a similar need for the case where there is a blank prev_line, you can add another case to the except block I think.