6

I know you're able to link the .replace() method to make multiple substring replacements.

But there's a problem when I do this:

phrase = "AppleBananaCarrot"
print(phrase.replace("Banana","Apple").replace("Apple","Banana"))

Here, I wanted Banana and Apple to swap, so that it printed: BananaAppleCarrot

Instead it printed: BananaBananaCarrot

In other words: I don't want a replacement substring to be replaced again. The only way I see this being solved is if there was a way to use the .replace() method simultaneously instead of subsequently. Does anyone know how to do that or something similar?

I tried looking on stackoverflow, but the questions were just asking how to do it subsequently more efficiently. I want to do it simultaneously. I couldn't find a question for that.

3
  • 3
    Does this answer your question? How to replace multiple substrings of a string? Commented Aug 22, 2022 at 14:29
  • No, most of the comments are replacing strings subsequently instead of simultaneously. The question itself doesn't make that distinction, as I tried to make here. Commented Aug 22, 2022 at 14:32
  • What does doing something in python simultaneously mean to you? Commented Aug 22, 2022 at 14:39

6 Answers 6

7

One trick we can try here is to use re.sub with a callback function:

import re

phrase = "AppleBananaCarrot"
output = re.sub(r'(?:apple|banana)', lambda m: 'Apple' if m.group().lower() == 'banana' else 'Banana', phrase, flags=re.I)
print(output)  # BananaAppleCarrot

The trick here is to make a single pass over the string and use logic to swap Apple for Banana and vice-versa. Note that we could try to do a three step replacement Apple -> (some other string) -> Banana, but the problem with this approach is that there is always the possibility that this intermediate string might happen to already be present in the input.

Sign up to request clarification or add additional context in comments.

Comments

2

This could be also a possible solution to that:

>>> f = lambda phrase, w1, w2: w2.join(word.replace(w2, w1) for word in phrase.split(w1))
>>> 
>>> phrase = "AppleBananaCarrot"
>>> print(f(phrase, 'Apple', 'Banana'))
BananaAppleCarrot

Comments

0

You will have to use placeholder (e.g. F1 and F2), otherwise you will not be able to distinguish between the original and the replaced substring. That is a solution if you want to only use String.replace.

phrase.replace("Banana","F1").replace("Apple","F2").replace("F1","Apple").replace("F2","Banana")

2 Comments

Here's the thing, the actual problem I'm dealing with is much more complex than the example I gave. I simplified it for the purposes of the question, but in my actual problem, I have to make a lot of replacements. Using the placeholder would take up too much code and would be prone to error.
You could generate that code with python and not be tied down to how many 'place holders` you felt like typing down
0

Here is my answer:

phrase = "AppleBananaCarrot"
print(phrase.replace("Banana","x").replace("Apple","Banana").replace("x", "Apple"))

2 Comments

If x happens to already be present in the input, then this approach will give unexpected results.
probably can use other string e.g. '---' that is not present in the input.
0

You may split the string on capital letters. Swap the first & second sub-strings, then re-join all the three sub-strings:

import re
# Splitting on UpperCase
split_cap = re.findall('[A-Z][^A-Z]*', phrase) 
split_cap[1]+split_cap[0]+split_cap[2]

Comments

0

you can make a function to do LinFelix answer automatically. The trick is to generate placeholder and check if they are present in the initial string or in newlist. if so, discard and generate another one.

import random
import string

def super_replace(s, oldlist, newlist):
    if len(oldlist) != len(newlist):
        return
        
    #generating placeholders
    phlist = []
    while len(phlist) < len(oldlist):
        ph = "<{[" + ''.join(random.choices(string.ascii_letters + string.digits, k=8)) + "]}>"
        if ph not in s and ph not in phlist and ph not in ''.join(newlist):
            phlist.append(ph)
    
    #replace oldlist with placeholder
    for i in range(len(oldlist)):
        s = s.replace(oldlist[i], phlist[i])
    
    #replace placeholder with newlist
    for i in range(len(oldlist)):
        s = s.replace(phlist[i], newlist[i])
    
    return s
    
    
phrase = "AppleBananaCarrot"
new_phrase = super_replace(phrase, ["Apple", "Banana"], ["Banana", "Apple"])
print(new_phrase)

output:

BananaAppleCarrot

you can also tweak the generation of placeholder so it doesn't required importing random and string by, for example, converting an int to base64

To minimize risk of unwanted behaviour if your substring are small, you can also test if one of the "old" substring is contained in the placeholder.

discard = False
for old in oldlist:
    if old in ph:
        discard = True
if ph not in s and ph not in phlist and ph not in ''.join(newlist) and not discard:
    phlist.append(ph)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.