it-swarm.com.de

Wie ersetze ich mehrere Teilstrings eines Strings?

Ich möchte die .replace-Funktion verwenden, um mehrere Zeichenfolgen zu ersetzen.

Ich habe derzeit

string.replace("condition1", "")

möchte aber sowas haben

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

obwohl sich das nicht nach guter Syntax anfühlt

was ist der richtige Weg, um dies zu tun? ein bisschen wie, wie in grep/regex können Sie \1 und \2, um Felder durch bestimmte Suchzeichenfolgen zu ersetzen

235
CQM

Hier ist ein kurzes Beispiel, das den Trick mit regulären Ausdrücken ausführen sollte:

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)

Zum Beispiel:

>>> pattern.sub(lambda m: rep[re.escape(m.group(0))], "(condition1) and --condition2--")
'() and --text--'
234
Andrew Clark

Sie könnten einfach eine nette kleine Schleifenfunktion machen.

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

dabei ist text die vollständige Zeichenfolge und dic ein Wörterbuch. Jede Definition ist eine Zeichenfolge, die eine Übereinstimmung mit dem Begriff ersetzt.

Anmerkung: in Python 3, iteritems() wurde ersetzt durch items()


Achtung: Python= Wörterbücher haben keine zuverlässige Reihenfolge für die Iteration. Diese Lösung löst Ihr Problem nur, wenn:

  • die Reihenfolge der Ersetzungen ist unerheblich
  • es ist in Ordnung, wenn ein Ersatz die Ergebnisse früherer Ersetzungen ändert

Zum Beispiel:

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

Mögliche Ausgabe Nr. 1:

"Das ist mein Schwein und das ist mein Schwein."

Mögliche Ausgabe # 2

"Das ist mein Hund und das ist mein Schwein."

Ein möglicher Fix ist die Verwendung eines 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")])
mySentence = "This is my cat and this is my dog."
replace_all(mySentence, od)
print(mySentence)

Ausgabe:

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

Vorsicht # 2: Ineffizient, wenn Ihre text Zeichenfolge zu groß ist oder das Wörterbuch viele Paare enthält.

108
Joseph Hansen

Hier ist eine Variante der ersten Lösung, die redu verwendet, falls Sie funktionsfähig sein möchten. :)

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

martineaus noch bessere version:

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

Warum nicht eine Lösung wie diese?

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
73
Enrico Bianchi

Dies ist nur eine knappe Zusammenfassung der großartigen Antworten von F.J. und MiniQuark. Alles, was Sie benötigen, um mehrere gleichzeitige Ersetzungen von Zeichenfolgen zu erreichen, ist die folgende Funktion:

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)

Verwendungszweck:

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

Wenn Sie möchten, können Sie ausgehend von dieser einfacheren Funktion eigene Ersatzfunktionen erstellen.

33
mmj

Ich habe dies auf der ausgezeichneten Antwort von F.J. aufgebaut:

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-Nutzung:

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

Da der Austausch nur in einem Durchgang erfolgt, ändert sich "Café" in "Tee", aber nicht zurück in "Café".

Wenn Sie dieselbe Ersetzung mehrmals durchführen müssen, können Sie auf einfache Weise eine Ersetzungsfunktion erstellen:

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

Verbesserungen:

  • code in eine Funktion verwandelt
  • unterstützung für mehrere Leitungen hinzugefügt
  • fehler bei der Flucht behoben
  • einfach, eine Funktion für einen bestimmten mehrfachen Wiedereinbau zu verursachen

Viel Spaß!: -)

28
MiniQuark

Ich möchte die Verwendung von String-Vorlagen vorschlagen. Platzieren Sie einfach die zu ersetzende Zeichenfolge in einem Wörterbuch und alles ist festgelegt! Beispiel aus 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'
20
Fredrik Pihl

In meinem Fall brauchte ich ein einfaches Ersetzen eindeutiger Schlüssel durch Namen, also dachte ich mir Folgendes:

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.'
12
James Koss

Hier meine $ 0.02. Es basiert auf Andrew Clarks Antwort, ist aber ein bisschen klarer und behandelt auch den Fall, dass eine zu ersetzende Zeichenfolge eine Teilzeichenfolge einer anderen zu ersetzenden Zeichenfolge ist (längere Zeichenfolge gewinnt).

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)

Es ist in diesem diese Übersicht , zögern Sie nicht, es zu ändern, wenn Sie einen Vorschlag haben.

9
bgusach

Beginnend Python 3.8 und die Einführung von Zuweisungsausdrücke (PEP 572) (:= Operator) können wir die Ersetzungen innerhalb eines Listenverständnisses anwenden:

# 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'
5
Xavier Guihot

Ich brauchte eine Lösung, bei der die zu ersetzenden Zeichenfolgen reguläre Ausdrücke sein können, um beispielsweise einen langen Text zu normalisieren, indem mehrere Leerzeichen durch ein einzelnes Zeichen ersetzt werden. Aufbauend auf einer Reihe von Antworten von anderen, einschließlich MiniQuark und mmj, habe ich mir Folgendes ausgedacht:

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)

Dies funktioniert für die Beispiele in anderen Antworten, zum Beispiel:

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

Das Wichtigste für mich ist, dass Sie auch reguläre Ausdrücke verwenden können, um beispielsweise nur ganze Wörter zu ersetzen oder Leerzeichen zu normalisieren:

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

Wenn Sie die Wörterbuchschlüssel als normale Zeichenfolgen verwenden möchten, können Sie diese maskieren, bevor Sie multiple_replace mit z. diese Funktion:

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"

Die folgende Funktion kann dabei helfen, fehlerhafte reguläre Ausdrücke in Ihren Wörterbuchschlüsseln zu finden (da die Fehlermeldung von multiple_replace nicht sehr aussagekräftig ist):

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

Beachten Sie, dass die Ersetzungen nicht verkettet, sondern gleichzeitig ausgeführt werden. Dies macht es effizienter, ohne die Leistungsfähigkeit einzuschränken. Um den Effekt der Verkettung nachzuahmen, müssen Sie möglicherweise nur weitere String-Ersetzungspaare hinzufügen und die erwartete Reihenfolge der Paare sicherstellen:

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

Hier ist ein Beispiel, das bei langen Saiten mit vielen kleinen Ersetzungen effizienter ist.

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)

Es geht darum, viele Verkettungen langer Zeichenfolgen zu vermeiden. Wir zerlegen die Quellzeichenfolge in Fragmente und ersetzen einige der Fragmente bei der Erstellung der Liste. Anschließend fügen wir das Ganze wieder zu einer Zeichenfolge zusammen.

2
9000

Ich weiß nichts über Geschwindigkeit, aber das ist meine tägliche schnelle Lösung:

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

... aber ich mag die # 1 Regex-Antwort oben. Hinweis - Wenn ein neuer Wert eine Teilzeichenfolge eines anderen Werts ist, ist die Operation nicht kommutativ.

1
del_hol

Du solltest es wirklich nicht so machen, aber ich finde es einfach viel zu cool:

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

Nun ist answer das Ergebnis aller Ersetzungen der Reihe nach

auch dies ist sehr hacky und ist nicht etwas, das Sie regelmäßig verwenden sollten. Aber es ist nur schön zu wissen, dass Sie so etwas tun können, wenn Sie es jemals brauchen.

0
inspectorG4dget

Sie können die Bibliothek pandas und die Funktion replace verwenden, die sowohl exakte Übereinstimmungen als auch Regex-Ersetzungen unterstützt. Zum Beispiel:

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

Und der geänderte Text ist:

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

Sie können ein Beispiel finden hier . Beachten Sie, dass die Ersetzungen im Text in der Reihenfolge erfolgen, in der sie in den Listen angezeigt werden

0
George Pipis

das ist meine Lösung für das Problem. Ich habe es in einem Chatbot verwendet, um die verschiedenen Wörter auf einmal zu ersetzen.

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

das wird The cat hunts the dog

0
emorjon2

Ein weiteres Beispiel: Eingabeliste

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

Die gewünschte Ausgabe wäre

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]] 
0
Akhil Thayyil

Hier ist eine andere Möglichkeit, dies mit einem Wörterbuch zu tun:

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

Ich schlage vor, dass der Code zum Beispiel sein sollte:

z = "My name is Ahmed, and I like coding "
print(z.replace(" Ahmed", " Dauda").replace(" like", " Love" ))

Es werden alle Änderungen wie gewünscht ausgedruckt.

0
Ahmed dauda

Oder nur für einen schnellen 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)
0
Brandon H

Ausgehend von der wertvollen Antwort von Andrew entwickelte ich ein Skript, das das Wörterbuch aus einer Datei lädt und alle Dateien im geöffneten Ordner aufbereitet, um die Ersetzungen vorzunehmen. Das Skript lädt die Zuordnungen aus einer externen Datei, in der Sie das Trennzeichen festlegen können. Ich bin ein Anfänger, aber ich fand dieses Skript sehr nützlich, wenn ich mehrere Ersetzungen in mehreren Dateien durchführte. Es lud ein Wörterbuch mit mehr als 1000 Einträgen in Sekunden. Es ist nicht elegant, aber es hat bei mir funktioniert

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()
0
Tommaso Sandi