1

I have a list with each item being a string. I want to do a search and replace in this list, but the replace may happen across multiple items. The replaced string goes to the first item and subequent items becomes blank. It's easier to explain with examples (not an exhaustive list of variations).

str_list = ["abc", "de", "fg", "hij", "abcde", "klm"]

def replace_parts(input_list, find_str, replace_str):
    """Function which will do the trick"""
    ...

# case1
replace_parts(str_list, "ab", "xy")
print(str_list)
# ["xyc", "de", "fg", "hij", "xycde", "klm"]

# case2
replace_parts(str_list, "abcd", "xy")
print(str_list)
# ["xy", "e", "fg", "hij", "xye", "klm"]

# case3
replace_parts(str_list, "cdef", "xyz")
print(str_list)
# ["abxyz", "", "g", "hij", "abcde", "klm"]

I'd like to know if there are any libraries which can do this. or if there is a pythonic way of solving this problem.

Actually I am dealing with objects in python pptx module with paragraph and runs. Here's the code that I have come up with now. But it's still a bit buggy and I don't know if this is the right way to solve the whole problem.


def para_text_replace(para, find_string, replace_string):
    find_string = str(find_string)
    replace_string = str(replace_string)
    starting_pos = para.text.find(find_string)
    if starting_pos == -1:
        return # text not in paragraph
    txt_prev = ""
    for run in para.runs:        
        if len(txt_prev) <= starting_pos < len(txt_prev) + len(run.text):
            if run.text.find(find_string) != -1:
                run.text = run.text.replace(find_string, replace_string)
                return
            else:
                txt_prev = txt_prev + run.text
                run.text = run.text[:starting_pos - len(txt_prev)] + replace_string
        elif starting_pos < len(txt_prev) and starting_pos + len(find_string) >= len(txt_prev) + len(run.text):
            txt_prev = txt_prev + run.text
            run.text = ""
        elif len(txt_prev) < starting_pos + len(find_string) < len(txt_prev) + len(run.text):
            txt_prev = txt_prev + run.text
            run.text = run.text[starting_pos + len(find_string) - len(txt_prev):]
        else:
            txt_prev += run.text
martineau
  • 119,623
  • 25
  • 170
  • 301
najeem
  • 1,841
  • 13
  • 29
  • Can you please explain me case 3 - how we get to `xye` – nikeros Dec 13 '21 at 11:26
  • sorry, that was a typo. I'll fix that. – najeem Dec 13 '21 at 11:36
  • sorry I still don't get it - why starting from `abcde` and replacing pattern `cdef` with `xyz` you still get `abcde`. You have 3 characters matched, no? – nikeros Dec 13 '21 at 13:07
  • No. the find_string should be matched completely. The match can be distributed over multiple list items. – najeem Dec 13 '21 at 13:20
  • @najeem check out [this answer](https://stackoverflow.com/a/24813382/1902513) and the link below to code that will replace text across runs while preserving style. I think that is the use case you're trying to solve for here: https://github.com/python-openxml/python-docx/issues/30#issuecomment-879593691 – scanny Dec 14 '21 at 20:17
  • @scanny Thanks for the pointers. I'll try them out. I couldnt get the python-docx method to work with pptx yet. But will try again. – najeem Dec 15 '21 at 14:57

1 Answers1

0

str.replace() does fixed replacements. Use re.sub() instead to capture the input of replace function as word

import re
str_list = ["abc", "de", "fg", "hij", "abcde", "klm"]


def replace_parts(input_list, find_str, replace_str):
    for index, word in enumerate(input_list):
        if(find_str in word):
            input_list[index] = re.sub(find_str, replace_str, word)


replace_parts(str_list, "abcd", "xy")
print(str_list)

The Code is easy to read You can use list comprehension to make it better .

Mohamed Fathallah
  • 1,274
  • 1
  • 15
  • 17
  • Thanks for the answer. But, please read the question again! – najeem Dec 13 '21 at 11:43
  • @najeem , your code has typos first if condition there is not And, OR , and make sure you add ( ) brace if you try to check X>(Y+W) for example , this all I can help you with I am sorry – Mohamed Fathallah Dec 13 '21 at 11:51