如何替换字符串的多个子字符串?

发布于 2024-11-09 05:05:28 字数 322 浏览 0 评论 0原文

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

我目前有

string.replace("condition1", "")

,但想要有类似的东西,

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

尽管这感觉不像好的语法,

但正确的方法是什么?有点像在 grep/regex 中如何执行 \1\2 将字段替换为某些搜索字符串

I would like to use the .replace function to replace multiple strings.

I currently have

string.replace("condition1", "")

but would like to have something like

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

although that does not feel like good syntax

what is the proper way to do this? kind of like how in grep/regex you can do \1 and \2 to replace fields to certain search strings

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(29

错々过的事 2024-11-16 05:05:28

这是一个应该使用正则表达式来解决问题的简短示例:

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.items()) 
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--'

Here is a short example that should do the trick with regular expressions:

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.items()) 
pattern = re.compile("|".join(rep.keys()))
text = pattern.sub(lambda m: rep[re.escape(m.group(0))], text)

For example:

>>> pattern.sub(lambda m: rep[re.escape(m.group(0))], "(condition1) and --condition2--")
'() and --text--'
沧笙踏歌 2024-11-16 05:05:28

你可以做一个漂亮的小循环函数。

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:如果您的文本字符串太大或字典中有很多对,效率就会很低。

You could just make a nice little looping function.

def replace_all(text, dic):
    for i, j in dic.iteritems():
        text = text.replace(i, j)
    return text

where text is the complete string and dic is a dictionary — each definition is a string that will replace a match to the term.

Note: in Python 3, iteritems() has been replaced with items()


Careful: Python dictionaries don't have a reliable order for iteration. This solution only solves your problem if:

  • order of replacements is irrelevant
  • it's ok for a replacement to change the results of previous replacements

Update: The above statement related to ordering of insertion does not apply to Python versions greater than or equal to 3.6, as standard dicts were changed to use insertion ordering for iteration.

For instance:

d = { "cat": "dog", "dog": "pig"}
my_sentence = "This is my cat and this is my dog."
replace_all(my_sentence, d)
print(my_sentence)

Possible output #1:

"This is my pig and this is my pig."

Possible output #2

"This is my dog and this is my pig."

One possible fix is to use an 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)

Output:

"This is my pig and this is my pig."

Careful #2: Inefficient if your text string is too big or there are many pairs in the dictionary.

北音执念 2024-11-16 05:05:28

为什么不采用这样的一种解决方案呢?

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

Why not one solution like this?

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
忘东忘西忘不掉你 2024-11-16 05:05:28

这是使用 reduce 的第一个解决方案的变体(从 functools 导入),如果您喜欢功能性的话。 :)

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)

Here is a variant of the first solution using reduce (import from functools), in case you like being functional. :)

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

martineau's even better version:

repls = ('hello', 'goodbye'), ('world', 'earth')
s = 'hello, world'
reduce(lambda a, kv: a.replace(*kv), repls, s)
人心善变 2024-11-16 05:05:28

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

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

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

This is just a more concise recap of F.J and MiniQuark great answers and last but decisive improvement by bgusach. All you need to achieve multiple simultaneous string replacements is the following function:

import re
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)

Usage:

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

If you wish, you can make your own dedicated replacement functions starting from this simpler one.

傻比既视感 2024-11-16 05:05:28

Python 3.8 开始,并引入赋值表达式 (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'

Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), we can apply the replacements within a list comprehension:

# 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'
南巷近海 2024-11-16 05:05:28

我将此建立在 FJ 的出色答案之上:

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!\"

改进:

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

享受! :-)

I built this upon F.J.s excellent answer:

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)

One shot usage:

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

Note that since replacement is done in just one pass, "café" changes to "tea", but it does not change back to "café".

If you need to do the same replacement many times, you can create a replacement function easily:

>>> 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!\"

Improvements:

  • turned code into a function
  • added multiline support
  • fixed a bug in escaping
  • easy to create a function for a specific multiple replacement

Enjoy! :-)

始终不够爱げ你 2024-11-16 05:05:28

我想建议使用字符串模板。只需将要替换的字符串放入字典中,一切就完成了!示例来自 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'

I would like to propose the usage of string templates. Just place the string to be replaced in a dictionary and all is set! Example from 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'
ゞ记忆︶ㄣ 2024-11-16 05:05:28

这是我的 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)

它在这个 这个要点,随意修改如果你有什么建议的话。

Here my $0.02. It is based on Andrew Clark's answer, just a little bit clearer, and it also covers the case when a string to replace is a substring of another string to replace (longer string wins)

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)

It is in this this gist, feel free to modify it if you have any proposal.

乖乖公主 2024-11-16 05:05:28

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

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

In my case, I needed a simple replacing of unique keys with names, so I thought this up:

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.'
睫毛上残留的泪 2024-11-16 05:05:28

我需要一个解决方案,其中要替换的字符串可以是正则表达式,
例如,通过用单个空白字符替换多个空白字符来帮助标准化长文本。建立在其他人(包括 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'

I needed a solution where the strings to be replaced can be a regular expressions,
for example to help in normalizing a long text by replacing multiple whitespace characters with a single one. Building on a chain of answers from others, including MiniQuark and mmj, this is what I came up with:

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)

It works for the examples given in other answers, for example:

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

The main thing for me is that you can use regular expressions as well, for example to replace whole words only, or to normalize white space:

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

If you want to use the dictionary keys as normal strings,
you can escape those before calling multiple_replace using e.g. this function:

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"

The following function can help in finding erroneous regular expressions among your dictionary keys (since the error message from multiple_replace isn't very telling):

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())

Note that it does not chain the replacements, instead performs them simultaneously. This makes it more efficient without constraining what it can do. To mimic the effect of chaining, you may just need to add more string-replacement pairs and ensure the expected ordering of the pairs:

>>> multiple_replace("button", {"but": "mut", "mutton": "lamb"})
'mutton'
>>> multiple_replace("button", [("button", "lamb"),
...                             ("but", "mut"), ("mutton", "lamb")])
'lamb'
戏蝶舞 2024-11-16 05:05:28

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

这是一个在具有许多小替换的长字符串上更有效的示例。

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)

重点是避免长字符串的多次串联。我们将源字符串切成片段,在形成列表时替换一些片段,然后将整个字符串重新连接回字符串。

Note: Test your case, see comments.

Here's a sample which is more efficient on long strings with many small replacements.

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)

The point is in avoiding many concatenations of long strings. We chop the source string to fragments, replacing some of the fragments as we form the list, and then join the whole thing back into a string.

素染倾城色 2024-11-16 05:05:28

您可以使用 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

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

You can use the pandas library and the replace function which supports both exact matches as well as regex replacements. For example:

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

And the modified text is:

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

You can find an example here. Notice that the replacements on the text are done with the order they appear in the lists

双手揣兜 2024-11-16 05:05:28

我也在为这个问题苦苦挣扎。对于许多替换,正则表达式很困难,并且比循环 string.replace 慢大约四倍(在我的实验条件下)。

您绝对应该尝试使用 Flashtext 库 (博客文章此处Github 此处)。 就我而言有点结束了每个文档的速度快了两个数量级,从 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”),则效果很好。

I was struggling with this problem as well. With many substitutions regular expressions struggle, and are about four times slower than looping string.replace (in my experiment conditions).

You should absolutely try using the Flashtext library (blog post here, Github here). In my case it was a bit over two orders of magnitude faster, from 1.8 s to 0.015 s (regular expressions took 7.7 s) for each document.

It is easy to find use examples in the links above, but this is a working example:

    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)

Note that Flashtext makes substitutions in a single pass (to avoid a --> b and b --> c translating 'a' into 'c'). Flashtext also looks for whole words (so 'is' will not match 'this'). It works fine if your target is several words (replacing 'This is' by 'Hello').

最偏执的依靠 2024-11-16 05:05:28

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

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

I was doing a similar exercise in one of my school homework. This was my solution

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

See result yourself on test string

string_to_change = 'I hate salad and vegetables'
print(normalize(string_to_change))
年华零落成诗 2024-11-16 05:05:28

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

REPLACEMENTS = {'<': '<', '>': '>', '&': '&'}

event_title = ''.join([REPLACEMENTS.get(c,c) for c in event['summary']])

I face similar problem today, where I had to do use .replace() method multiple times but it didn't feel good to me. So I did something like this:

REPLACEMENTS = {'<': '<', '>': '>', '&': '&'}

event_title = ''.join([REPLACEMENTS.get(c,c) for c in event['summary']])
坏尐絯 2024-11-16 05:05:28

我觉得这个问题需要一个单行递归 lambda 函数答案才能完整,只是因为。用法

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

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

注意:

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

注意:与Python中的所有递归函数一样,太大的递归深度(即太大的替换字典)将导致错误。请参阅此处

I feel this question needs a single-line recursive lambda function answer for completeness, just because. So there:

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

Usage:

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

Notes:

  • This consumes the input dictionary.
  • Python dicts preserve key order as of 3.6; corresponding caveats in other answers are not relevant anymore. For backward compatibility one could resort to a tuple-based version:
>>> mrep = lambda s, d: s if not d else mrep(s.replace(*d.pop()), d)
>>> mrep('abcabc', [('a', '1'), ('c', '2')])

Note: As with all recursive functions in python, too large recursion depth (i.e. too large replacement dictionaries) will result in an error. See e.g. here.

强者自强 2024-11-16 05:05:28

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

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

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

,这是非常 hacky并且不是您应该经常使用的东西。但很高兴知道如果您需要的话您可以做这样的事情。

You should really not do it this way, but I just find it way too cool:

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

Now, answer is the result of all the replacements in turn

again, this is very hacky and is not something that you should be using regularly. But it's just nice to know that you can do something like this if you ever need to.

煮茶煮酒煮时光 2024-11-16 05:05:28

要仅替换一个字符,请使用 translate ,而 str.maketrans 是我最喜欢的方法。

TL;博士> 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.

For replace only one character, use the translate and str.maketrans is my favorite method.

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


demo

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.
日暮斜阳 2024-11-16 05:05:28

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

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

I don't know about speed but this is my workaday quick fix:

reduce(lambda a, b: a.replace(*b)
    , [('o','W'), ('t','X')] #iterable of pairs: (oldval, newval)
    , 'tomato' #The string from which to replace values
    )

... but I like the #1 regex answer above. Note - if one new value is a substring of another one then the operation is not commutative.

夜无邪 2024-11-16 05:05:28

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

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

更换一次性完成。

Here is a version with support for basic regex replacement. The main restriction is that expressions must not contain subgroups, and there may be some edge cases:

Code based on @bgusach and others

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)

Tests

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]

The trick is to identify the matched group by its position. It is not super efficient (O(n)), but it works.

index = next((index for index,value in enumerate(matcher.groups()) if value), None)

Replacement is done in one pass.

两个我 2024-11-16 05:05:28

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

Starting from the precious answer of Andrew i developed a script that loads the dictionary from a file and elaborates all the files on the opened folder to do the replacements. The script loads the mappings from an external file in which you can set the separator. I'm a beginner but i found this script very useful when doing multiple substitutions in multiple files. It loaded a dictionary with more than 1000 entries in seconds. It is not elegant but it worked for me

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()
不再见 2024-11-16 05:05:28

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

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"})

这将变成猫猎狗

this is my solution to the problem. I used it in a chatbot to replace the different words at once.

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"})

this will become The cat hunts the dog

可是我不能没有你 2024-11-16 05:05:28

另一个例子:
输入列表

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

所需的输出将是

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

Code :

[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]] 

Another example :
Input list

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

The desired output would be

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

Code :

[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]] 
长发绾君心 2024-11-16 05:05:28

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

如果我们可以假设 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 现在是 'should modify string'

My approach would be to first tokenize the string, then decide for each token whether to include it or not.

Potentially, might be more performant, if we can assume O(1) lookup for a 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 is now 'should modify string'

梦幻的味道 2024-11-16 05:05:28

我知道这已经很旧了,但我正在尝试将 json 转换为 PHP,并且我喜欢使用括号 &新线路以查看每个替换将要执行的操作。

这是代码。

def do_syntax_changes(jsonInS):   
    """ generated by Joe
    see [How to replace multiple substrings of a string?](https://stackoverflow.com/q/6116978/601770)
        also see [How to replace multiple substrings of a string? >> Py3.8 assignment expressions](https://stackoverflow.com/a/55889140/601770)
    """
    
    phpOutS = ''
    for lineI in jsonInS:
        oS = (((((
        lineI.replace('null', 'NULL')
        ).replace('true', 'TRUE')
        ).replace('false', 'FALSE')
        ).replace(':', '=>')
        ).replace('{', '[')
        ).replace('}', ']') 
        phpOutS += oS
    return phpOutS

:)

它似乎也生成了很好的 PHP。

I know this is old but I was playing around with converting json to PHP and I liked using parentheses & new lines to see what each replacement was going to perform.

Here's the code.

def do_syntax_changes(jsonInS):   
    """ generated by Joe
    see [How to replace multiple substrings of a string?](https://stackoverflow.com/q/6116978/601770)
        also see [How to replace multiple substrings of a string? >> Py3.8 assignment expressions](https://stackoverflow.com/a/55889140/601770)
    """
    
    phpOutS = ''
    for lineI in jsonInS:
        oS = (((((
        lineI.replace('null', 'NULL')
        ).replace('true', 'TRUE')
        ).replace('false', 'FALSE')
        ).replace(':', '=>')
        ).replace('{', '[')
        ).replace('}', ']') 
        phpOutS += oS
    return phpOutS

:)

It seems to generate good PHP as well.

旧街凉风 2024-11-16 05:05:28

或者只是为了快速破解:

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)

Or just for a fast hack:

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)
念﹏祤嫣 2024-11-16 05:05: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)

Here is another way of doing it with a dictionary:

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)
-残月青衣踏尘吟 2024-11-16 05:05:28
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)
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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文