3

I am trapped in a quite straight forward problem, but after some tweak, I simply cannot find an easy and efficient algorithm to do this.

So basically I have a string, which contains certain elements, for instance:

l = "test %1, %13, %14, %15"

And a map:

dict = {"%1": "%33", "%13": "%14", "%14", "%15", "%15": "%17"}

And I would like to do the following stuff:

for k in dict.keys():
    l = l.replace(k, dict[k])

So what I am expecting is:

l = "test %33, %14, %15, %17"

But apparently this is not feasible, since there are some conflict between keys and values. So the above code would output:

l = "test %33, %17, %17, %17"

Sorry for such native problem, but how should I solve this and get my expected output? Note that the length of each key/value is not fixed, so I cannot do something like:

m_idx = l_copy.find(key)
l = l[:m_idx] + dict[key] + l[m_idx+len(key):]

Because the length is not fixed, the above code is still buggy.

Am I clear on this? Any suggestion would be appreciated very much!

======= update

So all keys follow this pattern of %[0-9]+.

lllllllllllll
  • 8,519
  • 9
  • 45
  • 80
  • `dict = {"%1": "%33", "%13": "%14", "%14", "%15", "%15": "%17"}` do you mean: `dict = {"%1": "%33", "%13": "%14", "%14": "%15", "%15": "%17"}` – KuboMD Jan 18 '19 at 19:14
  • 4
    Do all keys follow this pattern of %[0-9]+? – cs95 Jan 18 '19 at 19:16
  • 1
    Your problem is not well-constrained, for example, %13 in input matches both %13 and %1 in the translation table. Before the question is answerable, you'll need to provide extra clarification here about a) what is to be considered a boundary, and/or b) specify an order of priority when multiple overlapping replacements are possible. – wim Jan 18 '19 at 19:30
  • @coldspeed Yes! Sorry for the confusion. – lllllllllllll Jan 18 '19 at 19:32

1 Answers1

6

You can use re.sub with a lambda:

import re
l = "test %1, %13, %14, %15"
_dict = {"%1": "%33", "%13": "%14", "%14":"%15", "%15": "%17"}
new_l = re.sub('%\d+', lambda x:_dict[x.group()], l)

Output:

'test %33, %14, %15, %17'

You can use dict.get to prevent a KeyError by providing a default value should the key not be present in _dict:

new_l = re.sub('%\d+', lambda x:_dict.get(x.group(), x.group()), l)
Ajax1234
  • 69,937
  • 8
  • 61
  • 102