shahid hamdam
shahid hamdam

Reputation: 821

replace multiple words from a string at the same time

I have this dict in python.

reflections = {
    'I am': 'you are', 
    'I was': 'you were',
    'I': 'you',
    "I'm": 'you are',
    "I'd": 'you would',
    "I've": 'you have',
    "I'll": 'you will',
    'my': 'your',
    'you are': 'I am',
    'you were': 'I was',
    "you've": 'I have',
    "you'll": 'I will',
    'your': 'my',
    'yours': 'mine',
    'you': 'me',
    'me': 'you'
}

I have written this piece of code to replace the words.

see = "I am going to kill you"
for i in reflections:
    if i in see:
        print(f'matched key {i}')
        see = see.replace(i, reflections[i])
        print(see)

This is the output of the above code.

matched key I am
you are going to kill you
matched key you are
I am going to kill you
matched key you
I am going to kill me
matched key me
I am going to kill you

Now I want to replace all occurrences of words from reflections dict and replace them. As you can see in code output, "I am" is replaced with "you are" and in the next iteration, "you are" is again replaced with "I am", which shouldn't happen. It should not replace the replacement. So the output should be:

You are going to kill me

Upvotes: 1

Views: 116

Answers (2)

Czaporka
Czaporka

Reputation: 2407

Solution 1 - str.index

You can do it as follows:

  • create a new string variable new_see, which is initially empty, but will ultimately contain the result of the replacements
  • make each iteration only process the part of the input string up until the point where a matching key is encountered, and append the iteration's replacement result to the result string
  • after each iteration, truncate the input string from its start to the index after the key encountered in current iteration, so that the next iteration will only work with the yet unprocessed part
see = "I am going to kill you!"
new_see = ""
print(see)

for key, reflection in reflections.items():
    if key in see:
        idx = see.index(key)
        print(f"matched key [{key}] @ index {idx}, reflection=[{reflection}]")

        # take the part of `see` up until the index where the `key` ends,
        #  replace the `key` with `replacement` and append the result to
        #  the new string
        new_see += see[:idx+len(key)].replace(key, reflection)

        # truncate the original string from start up until the index where
        #  `key` was encountered, so the next iteration will only work on
        #  the part of it that hasn't been processed yet
        see = see[idx+len(key):]

        # take a look at the intermediate results
        print(f"see=[{see}], new_see=[{new_see}]")

# append any leftover part that wasn't in the dict (in this case, "!")
if see:
    new_see += see

new_see = new_see.capitalize()
print(new_see)

Output:

I am going to kill you!
matched key [I am] @ index 0, reflection=[you are]
see=[ going to kill you!], new_see=[you are]
matched key [you] @ index 15, reflection=[me]
see=[!], new_see=[you are going to kill me]
You are going to kill me!
Solution 2 - str.split

Slightly more pythonic solution using str.split instead of operating on indices:

see = "I am going to kill you!"
new_see = ""
print(see)

for key, reflection in reflections.items():
    if key in see:
        print(f"matched key [{key}], reflection=[{reflection}]")
        left, right = see.split(key)
        new_see += left + reflection
        see = right
        print(f"see=[{see}], new_see=[{new_see}]")
if see:
    new_see += see

new_see = new_see.capitalize()
print(new_see)

Output:

I am going to kill you!
matched key [I am], reflection=[you are]
see=[ going to kill you!], new_see=[you are]
matched key [you], reflection=[me]
see=[!], new_see=[you are going to kill me]
You are going to kill me!

As pointed out in a comment, this code is going to replace "I'm" with "You'm". In order to fix this, you should reorder the entries in your dict such that "I'm", "I'd", etc., are processed before "I". Even then though, it will still not work properly in some cases, e.g. for words in all caps - "DICT" is going to be replaced with "DyouCT". In order to deal with this, you'd need to take a look at regular expressions and use re.sub instead of str.replace - that will allow you e.g. to only replace a key if it's a standalone word (i.e. surrounded by non-letters).

Upvotes: 2

DUDANF
DUDANF

Reputation: 3000

print(see1) has the wrong level of indentation.

Try with this:

see = "you are going to kill me"
for i in reflections:
    if i in see:
        see = see.replace(i, reflections[i])
        see1 = see.replace(i, reflections[i])
print(see1)

That way you print the word once you have broken out of the for-loop.

Upvotes: 0

Related Questions