php具有以下strtr 功能:
strtr('aa-bb-cc', array('aa' => 'bbz', 'bb' => 'x', 'cc' => 'y'));
# bbz-x-y
Run Code Online (Sandbox Code Playgroud)
它用相应的值替换字符串中的字典键,并且(重要)不替换已经替换的字符串.一个天真的尝试在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'})
Run Code Online (Sandbox Code Playgroud)
回报xz-x-y不是我们想要的(bb再次被替换).如何更改上面的函数,使其行为像它的PHP对应?
(如果可能的话,我更喜欢没有正则表达式的答案).
Upd:这里有一些很棒的答案.我计时他们发现,对于短串Gumbo的版本似乎是最快的,在更长的字符串上,赢家是re解决方案:
# '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
Run Code Online (Sandbox Code Playgroud)
我自己的版本(稍微优化了Gumbo):
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)
Run Code Online (Sandbox Code Playgroud)
完整的代码和时间:https://gist.github.com/2889181
以下使用正则表达式来执行此操作:
import re
def strtr(s, repl):
pattern = '|'.join(map(re.escape, sorted(repl, key=len, reverse=True)))
return re.sub(pattern, lambda m: repl[m.group()], s)
print(strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'}))
Run Code Online (Sandbox Code Playgroud)
与PHP的版本一样,这会优先考虑更长的匹配.
def strtr(strng, replace):
if replace and strng:
s, r = replace.popitem()
return r.join(strtr(subs, dict(replace)) for subs in strng.split(s))
return strng
j=strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'})
assert j=='bbz-x-y', j
Run Code Online (Sandbox Code Playgroud)
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.
def strtr(strng, replace):
buffer = []
i, n = 0, len(strng)
while i < n:
match = False
for s, r in replace.items():
if strng[i:len(s)+i] == s:
buffer.append(r)
i = i + len(s)
match = True
break
if not match:
buffer.append(strng[i])
i = i + 1
return ''.join(buffer)
Run Code Online (Sandbox Code Playgroud)