If you replace each word one at a time, you can replace the words several times (and not get what you want). To avoid this, you can use a function or lambda:
d = {'bean':'robert', 'beans':'cars'} str_in = 'bean likes to sell his beans' str_out = re.sub(r'\b(\w+)\b', lambda m:d.get(m.group(1), m.group(1)), str_in)
Thus, as soon as the bean is replaced by robert , it will not be changed again (even if robert also in your word entry list).
As suggested by georg , I edited this answer using dict.get(key, default_value) . Alternative solution (also suggested by georg ):
str_out = re.sub(r'\b(%s)\b' % '|'.join(d.keys()), lambda m:d.get(m.group(1), m.group(1)), str_in)
seb
source share