php has the strtr function:
strtr('aa-bb-cc', array('aa' => 'bbz', 'bb' => 'x', 'cc' => 'y'));
# bbz-x-y
It replaces dictionary keys in a string with corresponding values and (important) doesn’t replace already replaced strings. A naive attempt to write the same in python:
def strtr(strng, replace):
for s, r in replace.items():
strng = strng.replace(s, r)
return strng
strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'})
returns xz-x-y which is not we want (bb got replaced again). How to change the above function so that it behaves like its php counterpart?
(I would prefer an answer without regular expressions, if possible).
Upd: some great answers here. I timed them and found that for short strings Gumbo’s version appears to be the fastest, on longer strings the winner is the re solution:
# 'aa-bb-cc'
0.0258 strtr_thg
0.0274 strtr_gumbo
0.0447 strtr_kojiro
0.0701 strtr_aix
# 'aa-bb-cc'*10
0.1474 strtr_aix
0.2261 strtr_thg
0.2366 strtr_gumbo
0.3226 strtr_kojiro
My own version (which is slightly optimized Gumbo’s):
def strtr(strng, replace):
buf, i = [], 0
while i < len(strng):
for s, r in replace.items():
if strng[i:len(s)+i] == s:
buf.append(r)
i += len(s)
break
else:
buf.append(strng[i])
i += 1
return ''.join(buf)
Complete codes and timings: https://gist.github.com/2889181
Here is a naive algorithm:
Use an index to walk the original string character by character and check for each index whether one of the search strings is equal to the string from the current index on. If a match is found, push the replacement in a buffer and proceed the index by the length of the matched string. If no match is found, proceed the index by one. At the end, concatenate the strings in the buffer to a single string.