【问题标题】:How to replace multiple substrings of a string?如何替换字符串的多个子字符串?
【发布时间】:2011-09-01 07:09:56
【问题描述】:

我想使用 .replace 函数来替换多个字符串。

我现在有

string.replace("condition1", "")

但想拥有类似的东西

string.replace("condition1", "").replace("condition2", "text")

虽然这感觉不是很好的语法

这样做的正确方法是什么?有点像在 grep/regex 中你可以使用 \1\2 将字段替换为某些搜索字符串

【问题讨论】:

  • 您是否尝试了所有提供的解决方案?哪个更快?
  • 我花时间测试了不同场景下的所有答案。见stackoverflow.com/questions/59072514/…
  • 老实说,我更喜欢你的链式方法。我在寻找解决方案时登陆这里并使用了您的解决方案,它工作得很好。
  • @frakman1 +1。不知道为什么这没有得到更多的支持。所有其他方法使代码更难阅读。如果有要替换的函数传递数组,这将起作用。但是你的链式方法是最清楚的(至少有固定数量的替换)
  • 似乎简短的回答是:没有更好的方法来做到这一点。

标签: python text replace


【解决方案1】:

下面是一个简短的例子,可以用正则表达式来解决问题:

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--'

【讨论】:

  • 替换是一次性完成的。
  • dkamins:它不太聪明,甚至没有应有的聪明(我们应该在用“|”连接之前对键进行正则表达式转义)。为什么没有过度设计?因为这样我们一次性完成(=fast),并且我们同时进行所有替换,避免像"spamham sha".replace("spam", "eggs").replace("sha","md5")"eggmd5m md5" 而不是"eggsham md5" 之类的冲突
  • @AndrewClark 如果您能用 lambda 解释最后一行发生的事情,我将不胜感激。
  • 您好,我创建了一个小要点,其中包含此 sn-p 的更清晰版本。它也应该更有效:gist.github.com/bgusach/a967e0587d6e01e889fd1d776c5f3729
  • 对于 python 3,使用 items() 而不是 iteritems()。
【解决方案2】:

你可以做一个不错的小循环函数。

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 版本,因为标准 dicts 已更改为使用插入顺序进行迭代。

例如:

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:

“这是我的猪,这是我的猪。”

可能的输出 #2

“这是我的狗,这是我的猪。”

一种可能的解决方法是使用 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:如果您的 text 字符串太大或字典中有很多对,则效率会降低。

【讨论】:

  • 应用不同替换的顺序很重要 - 所以不要使用标准字典,而是考虑使用 OrderedDict - 或 2 元组列表。
  • 这使得迭代字符串两次...不利于性能。
  • 在性能方面它比 Valentin 说的更糟糕 - 它会遍历文本的次数与 dic 中的项目一样多!如果“文本”很小,但对大文本来说很糟糕。
  • 请注意,这可能会产生意想不到的结果,因为在第一次迭代中新插入的文本可以在第二次迭代中匹配。例如,如果我们天真地尝试用“B”替换所有“A”,用“C”替换所有“B”,则字符串“AB”将被转换为“CC”,而不是“BC”。
  • 注意:从 Python 3.7 开始,“dict 对象的插入顺序保存特性已被声明为 Python 语言规范的官方部分。” -- 3.7 Release Notes
【解决方案3】:

为什么没有这样的解决方案?

s = "The quick brown fox jumps over the lazy dog"
for r in (("brown", "red"), ("lazy", "quick")):
    s = s.replace(*r)

#output will be:  The quick red fox jumps over the quick dog

【讨论】:

  • 这个超级好用,简单便携。
  • 看起来不错,但不能像 in 那样替换正则表达式:for r in ((r'\s.', '.'), (r'\s,' , ',')):
  • 使其成为 1-liner: ss = [s.replace(*r) for r in (("brown", "red"), ("lazy", "quick"))] [0]
  • 这受到任何多个replace 方法的排序问题,"abc" 和你的替换是(("a", "b"), ("b", "a")) 你可能期望"bac" 但你得到"aac"。此外,每次调用都会扫描整个字符串存在性能问题,因此复杂度至少为O(number of replacements * len(s)),加上引擎盖下发生的任何字符串模式匹配。
  • @MarkK 这很聪明,但在内存方面非常昂贵,因为它列出了所有中间结果的巨大列表,只是将它们全部扔给垃圾收集器。 functools.reduce 会更尊重一点:reduce(lambda a, e: a.replace(*e), ("ab",), "abac")。无论哪种方式,我都不推荐这种方法(见上面的评论)。
【解决方案4】:

这是第一个使用 reduce 的解决方案的变体,以防您喜欢功能性。 :)

repls = {'hello' : 'goodbye', 'world' : 'earth'}
s = 'hello, world'
reduce(lambda a, kv: a.replace(*kv), repls.iteritems(), s)

martineau 的更好版本:

repls = ('hello', 'goodbye'), ('world', 'earth')
s = 'hello, world'
reduce(lambda a, kv: a.replace(*kv), repls, s)

【讨论】:

  • repls 制作成一个元组序列并取消iteritems() 调用会更简单。即repls = ('hello', 'goodbye'), ('world', 'earth')reduce(lambda a, kv: a.replace(*kv), repls, s)。在 Python 3 中也可以保持不变。
  • 不错!如果你使用 python3 使用 items 而不是 iteritems (现在在 dicts 东西中删除)。
  • @martineau:自从reduce has been removed 以来,这在python3 中没有改变是不正确的。
  • @normanius: reduce 仍然存在,但是它是 Python 3 中 functools 模块的一部分(参见 docs),所以当我说不变时,我的意思是一样的代码可以运行——尽管必须承认reduce 在必要时已经被imported,因为它不再是内置的。
  • 抛开语法不谈,这与manyothersolutionson这个页面基本相同,该页面存在时间复杂度差以及替换中的排序问题和意外行为。
【解决方案5】:

这只是对 F.J 和 MiniQuark 出色答案以及 bgusach 的最后但决定性改进的更简洁的回顾。实现同时替换多个字符串只需要以下函数:

def multiple_replace(string, rep_dict):
    pattern = re.compile("|".join([re.escape(k) for k in sorted(rep_dict,key=len,reverse=True)]), flags=re.DOTALL)
    return pattern.sub(lambda x: rep_dict[x.group(0)], string)

用法:

>>>multiple_replace("Do you like cafe? No, I prefer tea.", {'cafe':'tea', 'tea':'cafe', 'like':'prefer'})
'Do you prefer tea? No, I prefer cafe.'

如果您愿意,可以从这个更简单的函数开始制作自己的专用替换函数。

【讨论】:

  • 虽然这是一个很好的解决方案,但并发字符串替换不会给出与按顺序(链接)执行它们完全相同的结果——尽管这可能无关紧要。
  • 当然,使用rep_dict = {"but": "mut", "mutton": "lamb"},字符串"button" 会在您的代码中生成"mutton",但如果替换项被链接起来,则会一个接一个地给出"lamb"
  • 这是这段代码的主要特点,不是缺陷。使用链式替换,它无法像我的示例中那样实现同时替换两个单词的期望行为。
  • 如果您不需要它,它似乎不是一个很棒的功能。但是这里我们说的是同时替换,那么它确实是主要功能。使用“链式”替换,该示例的输出将是 Do you prefer cafe? No, I prefer cafe.,这根本不可取。
  • @David 写你自己的答案,你的编辑太激进了
【解决方案6】:

我根据 F.J. 的出色回答构建了这个:

import re

def multiple_replacer(*key_values):
    replace_dict = dict(key_values)
    replacement_function = lambda match: replace_dict[match.group(0)]
    pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
    return lambda string: pattern.sub(replacement_function, string)

def multiple_replace(string, *key_values):
    return multiple_replacer(*key_values)(string)

单次使用:

>>> replacements = (u"café", u"tea"), (u"tea", u"café"), (u"like", u"love")
>>> print multiple_replace(u"Do you like café? No, I prefer tea.", *replacements)
Do you love tea? No, I prefer café.

请注意,由于替换只是一次完成,因此“café”会更改为“tea”,但不会变回“café”。

如果您需要多次进行相同的替换,您可以轻松创建替换函数:

>>> my_escaper = multiple_replacer(('"','\\"'), ('\t', '\\t'))
>>> many_many_strings = (u'This text will be escaped by "my_escaper"',
                       u'Does this work?\tYes it does',
                       u'And can we span\nmultiple lines?\t"Yes\twe\tcan!"')
>>> for line in many_many_strings:
...     print my_escaper(line)
... 
This text will be escaped by \"my_escaper\"
Does this work?\tYes it does
And can we span
multiple lines?\t\"Yes\twe\tcan!\"

改进:

  • 将代码转换为函数
  • 添加了多行支持
  • 修复了转义错误
  • 轻松为特定的多重替换创建函数

尽情享受吧! :-)

【讨论】:

  • 有人可以为像我这样的python新手一步一步解释一下吗?
  • 这里是 python 新手,所以我将不完整地理解它。将 key_values 分解为要替换的内容(由“|”连接的键)和逻辑(如果匹配是键,则返回值) b.制作一个正则表达式解析器(查找键并使用给定逻辑的“模式”) - 将其包装在 lambda 函数中并返回。我现在正在查找的东西:re.M,以及 lambda 替换逻辑的必要性。
  • @Fox 你明白了。您可以定义一个函数而不是使用 lambda,这只是为了使代码更短。但请注意,pattern.sub 需要一个只有一个参数(要替换的文本)的函数,因此该函数需要能够访问 replace_dictre.M 允许多行替换(文档中有很好的解释:docs.python.org/2/library/re.html#re.M)。
  • 这是一个 智能 答案,因为它通过对字符串进行单次扫描来处理重叠和交换。这个问题的许多其他答案都是陷阱……
【解决方案7】:

Python 3.8 开始,并引入assignment expressions (PEP 572):= 运算符),我们可以在列表理解中应用替换:

# text = "The quick brown fox jumps over the lazy dog"
# replacements = [("brown", "red"), ("lazy", "quick")]
[text := text.replace(a, b) for a, b in replacements]
# text = 'The quick red fox jumps over the quick dog'

【讨论】:

  • 你知道这是否比在循环中使用替换更有效吗?我正在测试所有答案的性能,但我还没有 3.8。
  • 为什么我会得到一个列表中的输出?
  • @johnrao07 好吧,列表理解构建了一个列表。这就是为什么在这种情况下,你会得到['The quick red fox jumps over the lazy dog', 'The quick red fox jumps over the quick dog']。但是赋值表达式 (text := text.replace) 也通过改变它来迭代地构建 text 的新版本。在列表理解之后,您可以使用包含修改后文本的text 变量。
  • 如果你想将新版本的text作为单行返回,你也可以使用[text := text.replace(a, b) for a, b in replacements][-1](注意[-1]),它会提取列表推导的最后一个元素;即text的最新版本。
  • 如果您只需要最后一个元素,这将是一种巨大的空间浪费。不要将列表推导用作reducers,尽管链接的答案不是特别有效或有用,因为它会遇到替换排序问题,就像这样。
【解决方案8】:

我想建议使用字符串模板。只需将要替换的字符串放入字典中即可!来自docs.python.org的示例

>>> from string import Template
>>> s = Template('$who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes kung pao'
>>> d = dict(who='tim')
>>> Template('Give $who $100').substitute(d)
Traceback (most recent call last):
[...]
ValueError: Invalid placeholder in string: line 1, col 10
>>> Template('$who likes $what').substitute(d)
Traceback (most recent call last):
[...]
KeyError: 'what'
>>> Template('$who likes $what').safe_substitute(d)
'tim likes $what'

【讨论】:

  • 看起来不错,但是当添加substitute 中未提供的密钥时会引发异常,因此在从用户那里获取模板时要小心。
  • 这种方法的一个缺点是模板必须包含所有要替换的 $strings,但不能超过所有,请参阅here
【解决方案9】:

就我而言,我需要用名称简单地替换唯一键,所以我想到了这个:

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.'

【讨论】:

  • 只要您没有替换冲突就可以使用。如果你用s 替换i,你会得到一个奇怪的行为。
  • 如果顺序很重要,您可以使用数组代替上面的 dict:b = [ ['i', 'Z'], ['s', 'Y'] ]; for x,y in (b): a = a.replace(x, y) 然后,如果您小心地对数组对进行排序,您可以确保不会递归地替换()。
  • 看来dicts now maintain order,来自 Python 3.7.0。我对其进行了测试,它在我的机器上使用最新的稳定 Python 3 按顺序运行。
  • 这与此页面上的大多数其他答案有何不同?
【解决方案10】:

这是我的 0.02 美元。它基于 Andrew Clark 的回答,稍微清楚一点,并且还涵盖了要替换的字符串是要替换的另一个字符串的子字符串的情况(更长的字符串获胜)

def multireplace(string, replacements):
    """
    Given a string and a replacement map, it returns the replaced string.

    :param str string: string to execute replacements on
    :param dict replacements: replacement dictionary {value to find: value to replace}
    :rtype: str

    """
    # Place longer ones first to keep shorter substrings from matching
    # where the longer ones should take place
    # For instance given the replacements {'ab': 'AB', 'abc': 'ABC'} against 
    # the string 'hey abc', it should produce 'hey ABC' and not 'hey ABc'
    substrs = sorted(replacements, key=len, reverse=True)

    # Create a big OR regex that matches any of the substrings to replace
    regexp = re.compile('|'.join(map(re.escape, substrs)))

    # For each match, look up the new string in the replacements
    return regexp.sub(lambda match: replacements[match.group(0)], string)

在这个this gist,有什么建议可以随时修改。

【讨论】:

  • 这应该是公认的答案,因为正则表达式是由所有键构成的,方法是按长度的降序对它们进行排序并用 | 连接它们。正则表达式交替运算符。并且排序是必要的,以便在有任何选择的情况下选择所有可能选择中最长的一个。
  • 我同意这是最好的解决方案,这要归功于排序。除了排序与我原来的答案相同,所以我也为我的解决方案借用了排序,以确保没有人会错过如此重要的功能。
【解决方案11】:

我需要一个解决方案,其中要替换的字符串可以是正则表达式, 例如,通过将多个空白字符替换为单个字符来帮助规范化长文本。基于其他人(包括 MiniQuark 和 mmj)的一系列答案,我得出了以下结论:

def multiple_replace(string, reps, re_flags = 0):
    """ Transforms string, replacing keys from re_str_dict with values.
    reps: dictionary, or list of key-value pairs (to enforce ordering;
          earlier items have higher priority).
          Keys are used as regular expressions.
    re_flags: interpretation of regular expressions, such as re.DOTALL
    """
    if isinstance(reps, dict):
        reps = reps.items()
    pattern = re.compile("|".join("(?P<_%d>%s)" % (i, re_str[0])
                                  for i, re_str in enumerate(reps)),
                         re_flags)
    return pattern.sub(lambda x: reps[int(x.lastgroup[1:])][1], string)

它适用于其他答案中给出的示例,例如:

>>> multiple_replace("(condition1) and --condition2--",
...                  {"condition1": "", "condition2": "text"})
'() and --text--'

>>> multiple_replace('hello, world', {'hello' : 'goodbye', 'world' : 'earth'})
'goodbye, earth'

>>> multiple_replace("Do you like cafe? No, I prefer tea.",
...                  {'cafe': 'tea', 'tea': 'cafe', 'like': 'prefer'})
'Do you prefer tea? No, I prefer cafe.'

对我来说最主要的是你也可以使用正则表达式,例如只替换整个单词,或者规范化空格:

>>> s = "I don't want to change this name:\n  Philip II of Spain"
>>> re_str_dict = {r'\bI\b': 'You', r'[\n\t ]+': ' '}
>>> multiple_replace(s, re_str_dict)
"You don't want to change this name: Philip II of Spain"

如果您想将字典键用作普通字符串, 您可以在调用 multiple_replace 之前使用例如逃避那些这个函数:

def escape_keys(d):
    """ transform dictionary d by applying re.escape to the keys """
    return dict((re.escape(k), v) for k, v in d.items())

>>> multiple_replace(s, escape_keys(re_str_dict))
"I don't want to change this name:\n  Philip II of Spain"

以下函数可以帮助您在字典键中查找错误的正则表达式(因为来自 multiple_replace 的错误消息不是很清楚):

def check_re_list(re_list):
    """ Checks if each regular expression in list is well-formed. """
    for i, e in enumerate(re_list):
        try:
            re.compile(e)
        except (TypeError, re.error):
            print("Invalid regular expression string "
                  "at position {}: '{}'".format(i, e))

>>> check_re_list(re_str_dict.keys())

请注意,它不会链接替换,而是同时执行它们。这使它更有效率,而不会限制它可以做什么。为了模仿链接的效果,您可能只需要添加更多的字符串替换对并确保对的预期顺序:

>>> multiple_replace("button", {"but": "mut", "mutton": "lamb"})
'mutton'
>>> multiple_replace("button", [("button", "lamb"),
...                             ("but", "mut"), ("mutton", "lamb")])
'lamb'

【讨论】:

  • 这很好,谢谢。是否可以改进以允许在替换中使用反向引用?我还没有立即弄清楚如何添加它。
  • 我上面问题的答案是stackoverflow.com/questions/45630940/…
  • 嗨,我收到了这个脚本的错误TypeError: 'dict_items' object is not subscriptable。有人可以帮忙吗?
【解决方案12】:

注意:测试您的案例,请参阅 cmets。

这里有一个示例,它对带有许多小替换的长字符串更有效。

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)

关键是要避免长字符串的许多连接。我们将源字符串分割成片段,在形成列表时替换一些片段,然后将整个内容重新连接成一个字符串。

【讨论】:

  • 你有基准来支持这里的性能断言吗?
  • @ggorlen:实际上正好相反:根据我的测试,对于前几千字节内的字符串,长字符串替换和连接更快。
【解决方案13】:

您可以使用pandas 库和replace 函数,它支持完全匹配以及正则表达式替换。例如:

df = pd.DataFrame({'text': ['Billy is going to visit Rome in November', 'I was born in 10/10/2010', 'I will be there at 20:00']})

to_replace=['Billy','Rome','January|February|March|April|May|June|July|August|September|October|November|December', '\d{2}:\d{2}', '\d{2}/\d{2}/\d{4}']
replace_with=['name','city','month','time', 'date']

print(df.text.replace(to_replace, replace_with, regex=True))

而修改后的文字是:

0    name is going to visit city in month
1                      I was born in date
2                 I will be there at time

您可以找到一个示例here。请注意,文本上的替换是按照它们在列表中出现的顺序完成的

【讨论】:

    【解决方案14】:

    我也在努力解决这个问题。许多替换正则表达式很困难,并且比循环 string.replace 慢四倍(在我的实验条件下)。

    您绝对应该尝试使用 Flashtext 库(blog post hereGithub here)。 In my case 对于每个文档,它比快了两个数量级,从 1.8 秒到 0.015 秒(正则表达式需要 7.7 秒)

    在上面的链接中很容易找到使用示例,但这是一个有效的示例:

        from flashtext import KeywordProcessor
        self.processor = KeywordProcessor(case_sensitive=False)
        for k, v in self.my_dict.items():
            self.processor.add_keyword(k, v)
        new_string = self.processor.replace_keywords(string)
    

    请注意,Flashtext 在一次传递中进行替换(以避免 a --> bb --> c 将 'a' 翻译成 'c')。 Flashtext 还会查找整个单词(因此 'is' 不会匹配 'this')。如果您的目标是几个单词(将 'This is' 替换为 'Hello'),它就可以正常工作。

    【讨论】:

    • 如果您需要替换 HTML 标签,这将如何工作?例如。将&lt;p&gt; 替换为/n。我尝试了您的方法,但带有标签 flashtext 似乎无法解析它?
    • 我不确定为什么它没有按您的预期工作。一种可能性是这些标签没有用空格分隔,记住 Flashtext 会查找整个单词。解决此问题的一种方法是首先使用简单的替换,以便“Hi

      there”变为“Hi

      there”。完成后,您需要小心删除不需要的空格(也是简单的替换?)。希望对您有所帮助。

    • 谢谢,你能设置&lt;&gt; 来标记单词的结尾(但要包含在替换中)?
    • 我相信“单词”只用空格标记。也许您可以在“KeywordProcessor”中设置一些可选参数。否则请考虑上述方法:将“
    • 感谢您提及这个项目。它完美地解决了我的几个要求。
    【解决方案15】:

    我觉得这个问题需要一个单行递归 lambda 函数来回答完整性,只是因为。所以那里:

    >>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.popitem()), d)
    

    用法:

    >>> mrep('abcabc', {'a': '1', 'c': '2'})
    '1b21b2'
    

    注意事项:

    • 这会消耗输入字典。
    • Python dicts 自 3.6 起保留键顺序;其他答案中的相应警告不再相关。为了向后兼容,可以使用基于元组的版本:
    >>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.pop()), d)
    >>> mrep('abcabc', [('a', '1'), ('c', '2')])
    

    注意:与python中的所有递归函数一样,太大的递归深度(即太大的替换字典)会导致错误。参见例如here.

    【讨论】:

    • 我在使用大字典时遇到了 RecursionError!
    • @Pablo 很有趣。多大?请注意,所有递归函数都会发生这种情况。例如,请参见此处:stackoverflow.com/questions/3323001/…
    • 我的替换字典接近 10 万个术语...到目前为止,使用 string.replace 到目前为止是最好的方法。
    • @Pablo 在这种情况下你不能使用递归函数。一般来说,sys.getrecursionlimit() 是一对 1000,最大。使用循环或类似的东西,或尝试简化替换。
    • 是的,恐怕这里真的没有捷径。
    【解决方案16】:

    我今天遇到了类似的问题,我不得不多次使用 .replace() 方法,但我感觉不太好。所以我做了这样的事情:

    REPLACEMENTS = {'<': '&lt;', '>': '&gt;', '&': '&amp;'}
    
    event_title = ''.join([REPLACEMENTS.get(c,c) for c in event['summary']])
    

    【讨论】:

      【解决方案17】:

      对于只替换一个字符,使用translatestr.maketrans 是我最喜欢的方法。

      tl;dr > result_string = your_string.translate(str.maketrans(dict_mapping))


      演示

      my_string = 'This is a test string.'
      dict_mapping = {'i': 's', 's': 'S'}
      result_good = my_string.translate(str.maketrans(dict_mapping))
      result_bad = my_string
      for x, y in dict_mapping.items():
          result_bad = result_bad.replace(x, y)
      print(result_good)  # ThsS sS a teSt Strsng.
      print(result_bad)   # ThSS SS a teSt StrSng.
      

      【讨论】:

      • 我也喜欢 maketrans/translate!不幸的是,它对单词替换没有用,因为它只能替换单个字符
      【解决方案18】:

      你真的不应该这样做,但我觉得太酷了:

      >>> replacements = {'cond1':'text1', 'cond2':'text2'}
      >>> cmd = 'answer = s'
      >>> for k,v in replacements.iteritems():
      >>>     cmd += ".replace(%s, %s)" %(k,v)
      >>> exec(cmd)
      

      现在,answer 是所有替换的结果

      再次强调,这是非常 hacky,不应该经常使用。但是很高兴知道如果您需要,您可以做这样的事情。

      【讨论】:

        【解决方案19】:

        我不知道速度,但这是我的工作日快速修复:

        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 正则表达式答案。注意 - 如果一个新值是另一个值的子字符串,则该操作不可交换。

        【讨论】:

          【解决方案20】:

          我在学校的一项作业中做了类似的练习。这是我的解决方案

          dictionary = {1: ['hate', 'love'],
                        2: ['salad', 'burger'],
                        3: ['vegetables', 'pizza']}
          
          def normalize(text):
              for i in dictionary:
                  text = text.replace(dictionary[i][0], dictionary[i][1])
              return text
          

          在测试字符串上自己查看结果

          string_to_change = 'I hate salad and vegetables'
          print(normalize(string_to_change))
          

          【讨论】:

            【解决方案21】:

            从 Andrew 的宝贵回答开始,我开发了一个脚本,该脚本从文件加载字典并详细说明打开的文件夹中的所有文件以进行替换。该脚本从您可以设置分隔符的外部文件加载映射。我是一个初学者,但我发现这个脚本在多个文件中进行多次替换时非常有用。它在几秒钟内加载了一个包含 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()
            

            【讨论】:

              【解决方案22】:

              这是我解决问题的方法。我在聊天机器人中使用它来一次替换不同的单词。

              def mass_replace(text, dct):
                  new_string = ""
                  old_string = text
                  while len(old_string) > 0:
                      s = ""
                      sk = ""
                      for k in dct.keys():
                          if old_string.startswith(k):
                              s = dct[k]
                              sk = k
                      if s:
                          new_string+=s
                          old_string = old_string[len(sk):]
                      else:
                          new_string+=old_string[0]
                          old_string = old_string[1:]
                  return new_string
              
              print mass_replace("The dog hunts the cat", {"dog":"cat", "cat":"dog"})
              

              这将变成The cat hunts the dog

              【讨论】:

                【解决方案23】:

                另一个例子: 输入列表

                error_list = ['[br]', '[ex]', 'Something']
                words = ['how', 'much[ex]', 'is[br]', 'the', 'fish[br]', 'noSomething', 'really']
                

                期望的输出是

                words = ['how', 'much', 'is', 'the', 'fish', 'no', 'really']
                

                代码:

                [n[0][0] if len(n[0]) else n[1] for n in [[[w.replace(e,"") for e in error_list if e in w],w] for w in words]] 
                

                【讨论】:

                  【解决方案24】:

                  我的方法是首先对字符串进行标记,然后为每个标记决定是否包含它。

                  如果我们可以假设 O(1) 查找 hashmap/set,可能会更高效:

                  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 现在是 'should modify string'

                  【讨论】:

                    【解决方案25】:

                    这是一个支持基本 regex 替换的版本。主要限制是表达式不能包含子组,并且可能存在一些边缘情况:

                    基于@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)
                    

                    更换一次完成。

                    【讨论】:

                      【解决方案26】:
                      sentence='its some sentence with a something text'
                      
                      def replaceAll(f,Array1,Array2):
                          if len(Array1)==len(Array2):
                              for x in range(len(Array1)):
                                  return f.replace(Array1[x],Array2[x])
                      
                      newSentence=replaceAll(sentence,['a','sentence','something'],['another','sentence','something something'])
                      
                      print(newSentence)
                      

                      【讨论】:

                      • 单一方法不能多次返回
                      【解决方案27】:

                      或者只是为了快速破解:

                      for line in to_read:
                          read_buffer = line              
                          stripped_buffer1 = read_buffer.replace("term1", " ")
                          stripped_buffer2 = stripped_buffer1.replace("term2", " ")
                          write_to_file = to_write.write(stripped_buffer2)
                      

                      【讨论】:

                        【解决方案28】:

                        这是使用字典的另一种方法:

                        listA="The cat jumped over the house".split()
                        modify = {word:word for number,word in enumerate(listA)}
                        modify["cat"],modify["jumped"]="dog","walked"
                        print " ".join(modify[x] for x in listA)
                        

                        【讨论】:

                          猜你喜欢
                          • 2016-09-10
                          • 2016-12-03
                          • 2017-12-06
                          • 2015-11-09
                          • 2021-06-13
                          • 2016-03-24
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多