Can you use two dictionary values ​to replace text in Python?

Question:

What should I do if the output of my code has changed only two texts

dict_data = [{'test 2': '333','m': 'mm'}, {'sss': 'n','help': '5'}]

texts = ["test 2 text m and text", "text help sss"]

for text in texts:
    for dict_data_a in dict_data:
        out = " ".join(dict_data_a.get(ele, ele) for ele in text.split())
        print(out)

Something that waits for the output

333 2 text mm and text
text 5 n
Asked By: dadashzadeh

||

Answers:

Can you use two dictionary values ​to replace text in Python? Yes

You could use str.replace

for text in texts:
    for d in dict_data:
        for k,v in d.items():
            text = text.replace(k, v)
    print(text)

Output:

333 text mm and text
text 5 n
Answered By: Rahul K P

1st problem

You have a double loop. So you have 4 combinations: 1st text with 1st dict, 1st text with 2nd dict, 2nd text with 1st dict, …

2 of them are the ones you wanted. 2 others are.

Here, I surmise that you wanted to replace words of the 1st text with 1st dict, and 2nd text with 2nd dict.

So you need 1 loop. But iterating both list (text and dict) at the same time.

Simple (to understand) version

dict_data = [{'test 2': '333','m': 'mm'}, {'sss': 'n','help': '5'}]

texts = ["test 2 text m and text", "text help sss"]

for i in range(len(texts)):
    text=texts[i]
    dict_data_a=dict_data[i]
    out = " ".join(dict_data_a.get(ele, ele) for ele in text.split())
    print(out)

Or, more pythonesque one

dict_data = [{'test 2': '333','m': 'mm'}, {'sss': 'n','help': '5'}]
texts = ["test 2 text m and text", "text help sss"]

for text,dict_data_a in zip(texts, dict_data):
    out = " ".join(dict_data_a.get(ele, ele) for ele in text.split())
    print(out)

2nd problem

You are basing your replacement on words. Yet you have one replacement that cannot fit a word, since it is made of 2 words (test 2).

You can’t not just replace one substring by another with replace, because then you would be, for example, replacing all m by mm, even those that are just letters in a word. For example looming would be replaced by loomming.

So for that, there are certainly many solutions, but the easiest one would be using regex, I think.

import re
dict_data = [{'test 2': '333','m': 'mm'}, {'sss': 'n','help': '5'}]
texts = ["test 2 text m and text", "text help sss"]

for text,dict_data_a in zip(texts, dict_data):
    out = text
    for org,rep in dict_data_a.items():
        out = re.sub(r'(?<!w)'+org+'(?!w)', rep, out)
    print(out)

Here we replace each key by its associated value, but using a reg ex, consisting of the key (org), prefixed by a "look-behind" (?<!z) that make the patter matches only occurrence of org that are not preceded by a letter (w). And suffixed by a "look-ahred" (?!w) that also forces the pattern to match only occurrence of org that are not followed immediately by a letter.

So "m one" will be replace by "mm one". "two m three" by "two mm three", "four m" by "four mm". But "many or some boom" won’t turn into "mmany or somme boomm"

Answered By: chrslg

Here is my approach: It is easier to deal with one dictionary, than multiple ones, so I use collections.ChainMap to turn a list of dictionary (dict_data) into a single dictionary (replacements). Then it is a matter of writing a simple function to transform all the old text to new ones (replace_all).

import collections

def replace_all(text, lookup_dict):
    for old_value, new_value in lookup_dict.items():
        text = text.replace(old_value, new_value)
    return text

dict_data = [{'test 2': '333','m': 'mm'}, {'sss': 'n','help': '5'}]
texts = ["test 2 text m and text", "text help sss"]

replacements = collections.ChainMap(*dict_data)
new_texts = [replace_all(text, replacements) for text in texts]
print("n".join(new_texts))

Notes

  • replacements behave like a single, combined dictionary
  • The print statement is to produce the output

Output

333 text mm and text
text 5 n
Answered By: Hai Vu
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.