php的strtr for python

时间:2012-06-07 11:45:41

标签: python string

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对应?

(如果可能的话,我更喜欢没有正则表达式的答案)。

更新:这里有一些很棒的答案。我给他们计时并发现,对于短字符串,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

5 个答案:

答案 0 :(得分:6)

以下使用正则表达式来执行此操作:

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的版本一样,这会优先考虑更长的匹配。

答案 1 :(得分:5)

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

答案 2 :(得分:3)

这是一个天真的算法:

使用索引逐个字符地遍历原始字符串,并检查每个索引是否其中一个搜索字符串等于当前索引所在的字符串。如果找到匹配项,请在缓冲区中推送替换项,并按匹配字符串的长度继续索引。如果未找到匹配项,请按索引处理索引。最后,将缓冲区中的字符串连接成一个字符串。

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)

答案 3 :(得分:2)

str.translate是等效的,但只能映射到单个字符。

答案 4 :(得分:0)

这个帖子的答案太过时了。我们走了......

选项#1:使用str.format()函数来处理:

"Hello there {first_name} {last_name}".format(first_name="Bob", last_name="Roy")

选项#2:使用Template类

from string import Template
t = Template('Hello there $first_name $last_name')
t.substitute(first_name="Bob", last_name="Roy")

参考: Python String Formatting Best Practices