在Python中实现多个字符串替换的最快方法
有没有什么推荐的方法可以一次性替换多个字符串,而不是像这样一个一个地用replace
方法连接起来(也就是text.replace(a, b).replace(c, d).replace(e, f)...
)?比如说,你会怎么在Python中实现一个像PHP的htmlspecialchars
那样快速的函数?
我比较了三种方法:(1) 多次使用replace
,(2) 正则表达式方法,和(3) Matt Anderson的方法。
在进行10次测试后,结果如下:
对于100个字符:
TIME: 0 ms [ replace_method(str) ] TIME: 5 ms [ regular_expression_method(str, dict) ] TIME: 1 ms [ matts_multi_replace_method(list, str) ]
对于1000个字符:
TIME: 0 ms [ replace_method(str) ] TIME: 3 ms [ regular_expression_method(str, dict) ] TIME: 2 ms [ matts_multi_replace_method(list, str) ]
对于10000个字符:
TIME: 3 ms [ replace_method(str) ] TIME: 7 ms [ regular_expression_method(str, dict) ] TIME: 5 ms [ matts_multi_replace_method(list, str) ]
对于100000个字符:
TIME: 36 ms [ replace_method(str) ] TIME: 46 ms [ regular_expression_method(str, dict) ] TIME: 39 ms [ matts_multi_replace_method(list, str) ]
对于1000000个字符:
TIME: 318 ms [ replace_method(str) ] TIME: 360 ms [ regular_expression_method(str, dict) ] TIME: 320 ms [ matts_multi_replace_method(list, str) ]
对于3687809个字符:
TIME: 1.277524 sec [ replace_method(str) ] TIME: 1.290590 sec [ regular_expression_method(str, dict) ] TIME: 1.116601 sec [ matts_multi_replace_method(list, str) ]
所以要给Matt点赞,他在处理比较大的字符串时,超越了多次使用replace
的方法。
有没有人有想法,能在处理较小的字符串时超过他的做法?
3 个回答
你想要多快呢?还有,你的字符串有多大?
在另一个网站上,有一个相对简单的方法可以用正则表达式来完成这个任务。可能需要稍微调整一下,以处理正则表达式中的特殊字符;我没有仔细查看。
如果这个方法不够好,老实说,你可能需要写一些C语言代码。你可以构建一个简单的状态机来完成所有的替换,然后逐字节处理字符串,不需要回溯,这样就能真正完成工作。不过,我怀疑你能在不使用C语言和优化的情况下,超越正则表达式引擎的效率。
也许可以这样做?把文本分成几部分,首先替换第一个“from”项,然后递归地将每个部分再分成更小的部分,继续用下一个“from”项进行替换,依此类推,直到所有需要替换的项都处理完。最后,将每个部分用对应的“to”项连接起来,等递归函数完成后就可以得到结果。
下面的代码可能有点难理解(我写的时候也觉得难),但看起来是按预期工作的。我没有进行性能测试,但我觉得它应该运行得还不错。
def multi_replace(pairs, text):
stack = list(pairs)
stack.reverse()
def replace(stack, parts):
if not stack:
return parts
# copy the stack so I don't disturb parallel recursions
stack = list(stack)
from_, to = stack.pop()
#print 'split (%r=>%r)' % (from_, to), parts
split_parts = [replace(stack, part.split(from_)) for part in parts]
parts = [to.join(split_subparts) for split_subparts in split_parts]
#print 'join (%r=>%r)' % (from_, to), parts
return parts
return replace(stack, [text])[0]
print multi_replace(
[('foo', 'bar'), ('baaz', 'foo'), ('quux', 'moop')],
'foobarbaazfooquuxquux')
接下来:
barbarfoobarmoopmoop
通常来说,.replace
方法的表现比其他方法要好。(可以参考我上面的测试结果。)