提问人:meder omuraliev 提问时间:3/8/2010 最后编辑:Karl Knechtelmeder omuraliev 更新时间:11/18/2023 访问量:78805
如何使用字典对字符串进行多次替换?
How can I make multiple replacements in a string using a dictionary?
问:
假设我们有:
d = {
'Спорт':'Досуг',
'russianA':'englishA'
}
s = 'Спорт russianA'
我怎样才能用相应的值替换任何键中的每个外观(在这种情况下,结果将是)?s
d
'Досуг englishA'
答:
一种方式,没有 RE
d = {
'Спорт':'Досуг',
'russianA':'englishA'
}
s = 'Спорт russianA'.split()
for n,i in enumerate(s):
if i in d:
s[n]=d[i]
print ' '.join(s)
评论
与 ghostdog74 几乎相同,但独立创建。一个区别, 使用 d.get() 代替 d[] 可以处理不在字典中的项目。
>>> d = {'a':'b', 'c':'d'}
>>> s = "a c x"
>>> foo = s.split()
>>> ret = []
>>> for item in foo:
... ret.append(d.get(item,item)) # Try to get from dict, otherwise keep value
...
>>> " ".join(ret)
'b d x'
您可以使用reduce函数:
reduce(lambda x, y: x.replace(y, dict[y]), dict, s)
评论
reduce
{ 'red': 'green', 'green': 'red'}
reduce
.replace()
html.replace('"', '"').replace('&', '&')
html = '"foo"'
使用 re:
import re
s = 'Спорт not russianA'
d = {
'Спорт':'Досуг',
'russianA':'englishA'
}
keys = (re.escape(k) for k in d.keys())
pattern = re.compile(r'\b(' + '|'.join(keys) + r')\b')
result = pattern.sub(lambda x: d[x.group()], s)
# Output: 'Досуг not englishA'
这将仅匹配整个单词。如果不需要,请使用以下模式:
pattern = re.compile('|'.join(re.escape(k) for k in d.keys()))
请注意,在这种情况下,如果某些字典条目是其他字典条目的子字符串,则应按长度对单词进行降序排序。
评论
.join(d.keys())
.join(re.escape(key) for key in d.keys())
https://regex101.com/r/bliVUS/1
\b
在这里找到的解决方案(我喜欢它的简单性):
def multipleReplace(text, wordDict):
for key in wordDict:
text = text.replace(key, wordDict[key])
return text
评论
我在类似的情况下使用它(我的字符串都是大写的):
def translate(string, wdict):
for key in wdict:
string = string.replace(key, wdict[key].lower())
return string.upper()
希望这在某种程度上有所帮助...... :)
评论
如果密钥有空间,则警告它失败,这是一个类似于 ghostdog74 的压缩解决方案,extaneons 回答:
d = {
'Спорт':'Досуг',
'russianA':'englishA'
}
s = 'Спорт russianA'
' '.join(d.get(i,i) for i in s.split())
使用正则表达式
我们可以通过创建正则表达式来匹配每个单独的键并将它们与 .我们习惯于进行替换,通过给它一个函数来执行替换(当然,这个函数将执行字典查找)。把它放在一起:|
re.sub
import re
# assuming global `d` and `s` as in the question
# a function that does the dict lookup with the global `d`.
def lookup(match):
return d[match.group()]
# Make the regex.
joined = '|'.join(re.escape(key) for key in d.keys())
pattern = re.compile(joined)
result = pattern.sub(lookup, s)
此处,用于转义替换中具有特殊含义的任何字符(以便它们不会干扰正则表达式的构建,并且按字面意思匹配)。re.escape
此正则表达式模式将与子字符串出现的任何位置匹配,即使它们是单词的一部分或跨越多个单词。为避免这种情况,请修改正则表达式,使其检查单词边界:
# pattern = re.compile(joined)
pattern = re.compile(rf'\b({joined})\b')
迭代使用str.replace
只需遍历查找字典,然后调用每个字典。由于此方法返回一个新字符串,并且不会(不能)就地修改字符串,因此我们必须在循环中重新分配结果:.items()
.replace
for to_replace, replacement in d.items():
s = s.replace(to_replace, replacement)
这种方法编写简单且易于理解,但它带有多个注意事项。
首先,它的缺点是它按特定顺序工作。也就是说,每个替换都有可能干扰其他替换。考虑:
s = 'one two'
s = s.replace('one', 'two')
s = s.replace('two', 'three')
这将产生 ,而不是 ,因为来自第一个替换的 本身将在第二步中被替换。这通常是不可取的;但是,在极少数情况下,当它应该以这种方式工作时,这种方法是唯一实用的方法。'three three'
'two three'
'two'
这种方法也不容易修复以尊重单词边界,因为它必须与文字文本匹配,并且“单词边界”可以以多种不同的方式标记 - 通过不同类型的空格,但也可以在字符串的开头和结尾没有文本。
最后,请记住,对于这种方法来说,a 并不是理想的数据结构。如果我们要遍历字典,那么它进行键查找的能力是无用的;而在 Python 3.5 及以下版本中,dict
s 的顺序是无法保证的(使顺序替换问题变得更糟)。相反,最好为替换指定一个元组列表:dict
d = [('Спорт', 'Досуг'), ('russianA', 'englishA')]
s = 'Спорт russianA'
for to_replace, replacement in d: # no more `.items()` call
s = s.replace(to_replace, replacement)
通过标记化
如果首先将字符串切成碎片(标记化),问题就会变得简单得多,这样一来,任何应该被替换的东西现在都与字典键完全匹配。这将允许直接使用字典的查找,并一次性处理整个字符串,同时也不需要构建自定义正则表达式。
假设我们想要匹配完整的单词。我们可以使用一个更简单的硬编码正则表达式,它将匹配空格,并使用捕获组;通过将其传递给 ,我们将字符串拆分为空格和非空格部分。因此:re.split
import re
tokenizer = re.compile('([ \t\n]+)')
tokenized = tokenizer.split(s)
现在我们在字典中查找每个标记:如果存在,则应将其替换为相应的值,否则应将其保留(相当于将其替换为自身)。字典方法非常适合这项任务。最后,我们将各个部分重新连接起来。因此:.get
s = ''.join(d.get(token, token) for token in tokenized)
更一般地说,例如,如果要替换的字符串中可能包含空格,则需要不同的标记化规则。但是,通常可以提出一个比第一部分中的正则表达式更简单的标记化规则(通过蛮力匹配所有键)。
特殊情况:替换单个字符
如果字典的键都是一个字符(从技术上讲,Unicode 码位),则可以使用更具体的技术。有关详细信息,请参阅替换字符串中多个字符的最佳方法?
一点点 lambda ...
# list of tuples version
(mrep:=lambda s,l: s if not l else mrep(s.replace(*l.pop()), l))
# dictionary version
(lambda s,d: (mrep:=lambda s,l : s if not l else
mrep(s.replace(*l.pop()), l))(s, list(d.items())))
# "universal" list/dict version
(lambda s,u: (mrep:=lambda s,l: s if not l else
mrep(s.replace(*l.pop()), l))(s, u if type(u)==type(list())
else list(u.items())))
评论
{'cat': 'russiancat'}
{'car':'russiancar', 'pet' : 'russianpet'}