womesiete
womesiete

Reputation: 351

How to Replace Dynamic Variables in String with Python

I am using the code below to find any words enclosed by "<<" and ">>" in a string and replace them with the relevant previously defined variable. This works, but is there a safer or more efficient way to accomplish this? I have seen several warnings about the use of eval, and my solution seems overly complicated.

import re

aa = 'alpha'
bb = 'beta'
cc = 'gamma'

teststr = 'A for <<aa>>, b means <<bb>>, and c could be <<cc>>.'

matches = re.finditer('<<(\w*)>>', teststr)

for i in matches:
    teststr = teststr.replace(i.group(0), eval(i.group(1)) )

print teststr

Upvotes: 0

Views: 7688

Answers (2)

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89557

Use a dictionary and a lambda function as replacement:

>>> import re
>>> teststr = 'A for <<aa>>, b means <<bb>>, and c could be <<cc>>.'
>>> dico = { 'aa':'alpha', 'bb':'beta', 'cc':'gamma' }
>>> re.sub(r'<<([^>]*)>>', lambda m: dico[m.group(1)], teststr)
'A for alpha, b means beta, and c could be gamma.'

If you are not sure that each string between << and >> exists as key in the dictionary, change [^>]* to an alternation with all available keys: aa|bb|cc. If you have to many keys and you don't want to make it by hand, you can build the pattern dynamically like this:

python 2.7:

>>> re.sub(r'<<(%s)>>'%"|".join(sorted(dico.keys(), reverse=True)), lambda x: dico[x.group(1)], teststr)

python 3.x:

>>> re.sub(r'<<({})>>'.format("|".join(sorted(dico.keys(), reverse=True))), lambda x: dico[x.group(1)], teststr)

Upvotes: 2

Terry Jan Reedy
Terry Jan Reedy

Reputation: 19144

Use a dict to get the substitution.

import re
d = {'aa': 'alpha', 'bb': 'beta', 'cc': 'gamma'}

teststr = 'A for <<aa>>, b means <<bb>>, and c could be <<cc>>.'
matches = re.finditer('<<(\w*)>>', teststr)
for i in matches:
    teststr = teststr.replace(i.group(0), d[i.group(1)])
print(teststr)

prints A for alpha, b means beta, and c could be gamma.

Upvotes: 1

Related Questions