我想使用.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来替换某些搜索字符串的字段
当前回答
从安德鲁的宝贵答案开始,我开发了一个脚本,从一个文件加载字典,并详细说明所有文件上打开的文件夹做替换。脚本从一个外部文件加载映射,您可以在该文件中设置分隔符。我是一个初学者,但我发现这个脚本在多个文件中做多个替换时非常有用。它在几秒钟内加载了一个包含1000多个条目的字典。这并不优雅,但对我来说很管用
import glob
import re
mapfile = input("Enter map file name with extension eg. codifica.txt: ")
sep = input("Enter map file column separator eg. |: ")
mask = input("Enter search mask with extension eg. 2010*txt for all files to be processed: ")
suff = input("Enter suffix with extension eg. _NEW.txt for newly generated files: ")
rep = {} # creation of empy dictionary
with open(mapfile) as temprep: # loading of definitions in the dictionary using input file, separator is prompted
for line in temprep:
(key, val) = line.strip('\n').split(sep)
rep[key] = val
for filename in glob.iglob(mask): # recursion on all the files with the mask prompted
with open (filename, "r") as textfile: # load each file in the variable text
text = textfile.read()
# start replacement
#rep = dict((re.escape(k), v) for k, v in rep.items()) commented to enable the use in the mapping of re reserved characters
pattern = re.compile("|".join(rep.keys()))
text = pattern.sub(lambda m: rep[m.group(0)], text)
#write of te output files with the prompted suffice
target = open(filename[:-4]+"_NEW.txt", "w")
target.write(text)
target.close()
其他回答
我觉得这个问题需要一个单行递归lambda函数的答案,只是因为。所以有:
>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.popitem()), d)
用法:
>>> mrep('abcabc', {'a': '1', 'c': '2'})
'1b21b2'
注:
这将消耗输入字典。 Python字典保留3.6起的键顺序;其他答案中的相应警告不再相关。为了向后兼容,可以使用基于元组的版本:
>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.pop()), d)
>>> mrep('abcabc', [('a', '1'), ('c', '2')])
注意:与python中的所有递归函数一样,太大的递归深度(即替换字典太大)将导致错误。请看这里。
你可以做一个漂亮的循环函数。
def replace_all(text, dic):
for i, j in dic.iteritems():
text = text.replace(i, j)
return text
其中text是完整的字符串,dic是字典-每个定义都是一个字符串,将替换与术语匹配的字符串。
注意:在Python 3中,iteritems()已被items()取代
注意:Python字典没有迭代的可靠顺序。此解决方案仅在以下情况下解决您的问题:
替换的顺序无关紧要 替换者可以改变之前替换者的结果
更新:上述与插入顺序相关的语句不适用于大于或等于3.6的Python版本,因为标准字典已更改为使用插入顺序进行迭代。
例如:
d = { "cat": "dog", "dog": "pig"}
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, d)
print(my_sentence)
可能输出#1:
"This is my pig and this is my pig."
可能的输出#2
"This is my dog and this is my pig."
一个可能的解决方法是使用OrderedDict。
from collections import OrderedDict
def replace_all(text, dic):
for i, j in dic.items():
text = text.replace(i, j)
return text
od = OrderedDict([("cat", "dog"), ("dog", "pig")])
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, od)
print(my_sentence)
输出:
"This is my pig and this is my pig."
注意事项#2:如果你的文本字符串太大或字典中有很多对,效率就会很低。
注意:测试你的案例,见注释。
这里有一个例子,它在长弦上更有效,有许多小的替换。
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)
关键是要避免长字符串的多次连接。我们将源字符串切成片段,在我们形成列表时替换一些片段,然后将整个字符串连接回字符串。
下面是一个简短的例子,应该做的技巧与正则表达式:
import re
rep = {"condition1": "", "condition2": "text"} # define desired replacements here
# use these three lines to do the replacement
rep = dict((re.escape(k), v) for k, v in rep.iteritems())
#Python 3 renamed dict.iteritems to dict.items so use rep.items() for latest versions
pattern = re.compile("|".join(rep.keys()))
text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text)
例如:
>>> pattern.sub(lambda m: rep[re.escape(m.group(0))], "(condition1) and --condition2--")
'() and --text--'
在我的情况下,我需要一个简单的唯一键替换名称,所以我想到了这个:
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.'