如果我想进行多个字符串替换,那么最有效的方法是什么?
我旅行中遇到的一种情况如下:
>>> strings = ['a', 'list', 'of', 'strings']
>>> [s.replace('a', '')...replace('u', '') for s in strings if len(s) > 2]
['a', 'lst', 'of', 'strngs']
答案 0 :(得分:10)
您给出的具体示例(删除单个字符)非常适合translate
字符串方法,单个字符替换为单个字符。如果输入字符串是Unicode,那么,以及上面两种“替换”,使用translate
方法替换具有多个字符串的单个字符也是可以的(如果您需要处理但字节字符串。
如果您需要替换多个字符的子字符串,那么我还建议使用正则表达式 - 尽管不是@ gnibbler的回答推荐的方式;相反,我会从r'onestring|another|yetanother|orthis'
构建正则表达式(加入你想要用竖线替换的子串 - 当然,如果它们包含特殊字符,也要确保它们re.escape
并写一个简单的替代 - 基于词典的功能。
我现在不打算提供很多代码,因为我不知道这两段中的哪一段适用于你的实际需要,但是(当我后来回到家并再次检查SO时;-)我我很乐意根据您对问题的编辑进行编辑以根据需要添加代码示例(比对此答案的评论更有用; - )。
编辑:在评论中OP表示他想要一个“更一般”的答案(没有澄清这意味着什么)然后在编辑他的Q时他说他想研究“权衡”在各种片段所有之间使用单字符子串(并检查其存在,而不是按原始请求替换 - 当然是完全不同的语义)。
鉴于这种完全混乱,我可以说是“检查权衡”(性能方面)我喜欢使用python -mtimeit -s'setup things here' 'statements to check'
(确保要检查的语句没有副作用以避免扭曲时间测量,因为timeit
隐式循环以提供精确的定时测量。)
一般答案(没有任何权衡,涉及多字符子串,完全违背他的Q编辑但与他的评论一致 - 两者完全矛盾, 当然不可能满足两个):
import re
class Replacer(object):
def __init__(self, **replacements):
self.replacements = replacements
self.locator = re.compile('|'.join(re.escape(s) for s in replacements))
def _doreplace(self, mo):
return self.replacements[mo.group()]
def replace(self, s):
return self.locator.sub(self._doreplace, s)
使用示例:
r = Replacer(zap='zop', zip='zup')
print r.replace('allazapollezipzapzippopzip')
如果要替换的某些子字符串是Python关键字,则需要稍微传递它们,例如,以下内容:
r = Replacer(abc='xyz', def='yyt', ghi='zzq')
会失败,因为def
是一个关键字,所以你需要例如:
r = Replacer(abc='xyz', ghi='zzq', **{'def': 'yyt'})
等。
我觉得这对于一个类(而不是程序编程)很有用,因为RE要定位要替换的子串,表示要替换它们的dict,以及执行替换的方法,真的叫出“保持一致“,类实例是在Python中执行这种”保持在一起“的正确方法。闭包工厂也可以工作(因为replace
方法实际上是需要在“外部”可见的实例的唯一部分)但是可能不太清楚,更难调试方式:
def make_replacer(**replacements):
locator = re.compile('|'.join(re.escape(s) for s in replacements))
def _doreplace(mo):
return replacements[mo.group()]
def replace(s):
return locator.sub(_doreplace, s)
return replace
r = make_replacer(zap='zop', zip='zup')
print r('allazapollezipzapzippopzip')
唯一真正的优势可能是一个非常适度的更好的性能(需要使用timeit
检查“基准案例”被认为是重要且代表使用它的应用程序)作为访问“自由变量”(在这种情况下,replacements
,locator
,_doreplace
)可能比在正常的基于类的方法中访问限定名称(self.replacements
等)要快一些(无论这个方法)是否会依赖于正在使用的Python实现,因此需要在重要的基准测试中使用timeit
进行检查!)。
答案 1 :(得分:0)
您可能会发现创建正则表达式并立即执行所有替换更快。
最好将替换代码移到一个函数中,以便您可以记住,如果列表中可能有重复项
>>> import re
>>> [re.sub('[aeiou]','',s) for s in strings if len(s) > 2]
['a', 'lst', 'of', 'strngs']
>>> def replacer(s, memo={}):
... if s not in memo:
... memo[s] = re.sub('[aeiou]','',s)
... return memo[s]
...
>>> [replacer(s) for s in strings if len(s) > 2]
['a', 'lst', 'of', 'strngs']