php有strtr函数:
strtr('aa-bb-cc', array('aa' => 'bbz', 'bb' => 'x', 'cc' => 'y'));
# bbz-x-y它用相应的值替换字符串中的字典键,并且(重要的)不替换已经被替换的字符串。用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'})返回我们不想要的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我自己的版本(略有优化的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)完整的代码和时间:https://gist.github.com/2889181
发布于 2012-06-07 20:10:54
下面是一个简单的算法:
使用索引逐字符遍历原始字符串,并检查每个索引中是否有一个搜索字符串等于从当前索引开始的字符串。如果找到匹配项,则在缓冲区中推送替换项,并按匹配字符串的长度继续索引。如果未找到匹配项,则按1继续索引。最后,将缓冲区中的字符串连接为单个字符串。
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)发布于 2012-06-07 20:40:10
下面使用正则表达式来完成此操作:
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'}))与PHP的版本一样,它优先考虑更长的匹配。
发布于 2012-06-07 20:51:38
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', jhttps://stackoverflow.com/questions/10931150
复制相似问题