我想使用.replace函数替换多个字符串。
我目前有
string.replace("condition1", "")
但想要一些像
string.replace("condition1", "").replace("condition2", "text")
尽管这样的语法感觉不太好
正确的做法是什么?有点像在grep/regex中,你可以用\1和\2来替换某些搜索字符串的字段
我想使用.replace函数替换多个字符串。
我目前有
string.replace("condition1", "")
但想要一些像
string.replace("condition1", "").replace("condition2", "text")
尽管这样的语法感觉不太好
正确的做法是什么?有点像在grep/regex中,你可以用\1和\2来替换某些搜索字符串的字段
当前回答
我的方法是首先将字符串标记化,然后决定每个标记是否包含它。
潜在地,如果我们可以假设一个hashmap/set的O(1)查找,可能会更好:
remove_words = {"we", "this"}
target_sent = "we should modify this string"
target_sent_words = target_sent.split()
filtered_sent = " ".join(list(filter(lambda word: word not in remove_words, target_sent_words)))
Filtered_sent现在是'应该修改字符串'
其他回答
你真的不应该这样做,但我觉得这太酷了:
>>> replacements = {'cond1':'text1', 'cond2':'text2'}
>>> cmd = 'answer = s'
>>> for k,v in replacements.iteritems():
>>> cmd += ".replace(%s, %s)" %(k,v)
>>> exec(cmd)
现在,答案是所有替换的结果
再说一次,这是非常俗气的,不是你应该经常使用的东西。但我很高兴知道如果你需要的话,你可以这样做。
在我的情况下,我需要一个简单的唯一键替换名称,所以我想到了这个:
a = 'This is a test string.'
b = {'i': 'I', 's': 'S'}
for x,y in b.items():
a = a.replace(x, y)
>>> a
'ThIS IS a teSt StrIng.'
下面是一个支持基本正则表达式替换的版本。主要的限制是表达式不能包含子组,并且可能存在一些边缘情况:
基于@bgusach和其他的代码
import re
class StringReplacer:
def __init__(self, replacements, ignore_case=False):
patterns = sorted(replacements, key=len, reverse=True)
self.replacements = [replacements[k] for k in patterns]
re_mode = re.IGNORECASE if ignore_case else 0
self.pattern = re.compile('|'.join(("({})".format(p) for p in patterns)), re_mode)
def tr(matcher):
index = next((index for index,value in enumerate(matcher.groups()) if value), None)
return self.replacements[index]
self.tr = tr
def __call__(self, string):
return self.pattern.sub(self.tr, string)
测试
table = {
"aaa" : "[This is three a]",
"b+" : "[This is one or more b]",
r"<\w+>" : "[This is a tag]"
}
replacer = StringReplacer(table, True)
sample1 = "whatever bb, aaa, <star> BBB <end>"
print(replacer(sample1))
# output:
# whatever [This is one or more b], [This is three a], [This is a tag] [This is one or more b] [This is a tag]
诀窍是通过位置来识别匹配的组。它不是超级高效(O(n)),但它是有效的。
index = next((index for index,value in enumerate(matcher.groups()) if value), None)
替换是一次完成的。
注意:测试你的案例,见注释。
这里有一个例子,它在长弦上更有效,有许多小的替换。
source = "Here is foo, it does moo!"
replacements = {
'is': 'was', # replace 'is' with 'was'
'does': 'did',
'!': '?'
}
def replace(source, replacements):
finder = re.compile("|".join(re.escape(k) for k in replacements.keys())) # matches every string we want replaced
result = []
pos = 0
while True:
match = finder.search(source, pos)
if match:
# cut off the part up until match
result.append(source[pos : match.start()])
# cut off the matched part and replace it in place
result.append(replacements[source[match.start() : match.end()]])
pos = match.end()
else:
# the rest after the last match
result.append(source[pos:])
break
return "".join(result)
print replace(source, replacements)
关键是要避免长字符串的多次连接。我们将源字符串切成片段,在我们形成列表时替换一些片段,然后将整个字符串连接回字符串。
我不知道速度如何,但这是我日常的快速解决方法:
reduce(lambda a, b: a.replace(*b)
, [('o','W'), ('t','X')] #iterable of pairs: (oldval, newval)
, 'tomato' #The string from which to replace values
)
... 但我喜欢上面的#1正则表达式答案。注意:如果一个新值是另一个值的子字符串,那么该操作是不可交换的。