sostituire - Come sostituire l'ultima occorrenza di un'espressione in una stringa?


139

Esiste un modo rapido in Python per sostituire le stringhe ma, invece di iniziare dall'inizio come replacefa, a partire dalla fine? Per esempio:

>>> def rreplace(old, new, occurrence)
>>>     ... # Code to replace the last occurrences of old by new

>>> '<div><div>Hello</div></div>'.rreplace('</div>','</bad>',1)
>>> '<div><div>Hello</div></bad>'

5
Bella domanda, a giudicare dalle complicate soluzioni a un problema così semplice.
Justin Ardini,

3
C'è un elegante one-liner nelle risposte di seguito che ha impiegato 9 anni (!) Per essere aggiunto a questa domanda, basta scorrere verso il basso per trovarla.
John D,

Risposte:


196
>>> def rreplace(s, old, new, occurrence):
...  li = s.rsplit(old, occurrence)
...  return new.join(li)
... 
>>> s
'1232425'
>>> rreplace(s, '2', ' ', 2)
'123 4 5'
>>> rreplace(s, '2', ' ', 3)
'1 3 4 5'
>>> rreplace(s, '2', ' ', 4)
'1 3 4 5'
>>> rreplace(s, '2', ' ', 0)
'1232425'

9
Molto bella! In un benchmark non scientifico di sostituzione dell'ultima occorrenza di un'espressione in una stringa tipica nel mio programma (> 500 caratteri), la tua soluzione era tre volte più veloce della soluzione di Alex e quattro volte più veloce della soluzione di Mark. Grazie a tutti per le vostre risposte!
Barthelemy,

2
Grazie, funziona Il .replacemetodo accetta un terzo argomento facoltativo "count" che gli dice di sostituire le prime n occorrenze. Non sarebbe stato intuitivo se ciò avesse richiesto un -1, ma sfortunatamente non lo sarebbe, quindi abbiamo bisogno della tua soluzione.
Cardamomo,

17

Non pretendo che questo sia il modo più efficiente di farlo, ma è un modo semplice. Inverte tutte le stringhe in questione, esegue una sostituzione ordinaria usando str.replacesulle stringhe invertite, quindi inverte il risultato indietro nel modo giusto:

>>> def rreplace(s, old, new, count):
...     return (s[::-1].replace(old[::-1], new[::-1], count))[::-1]
...
>>> rreplace('<div><div>Hello</div></div>', '</div>', '</bad>', 1)
'<div><div>Hello</div></bad>'

10

Ecco un one-liner:

result = new.join(s.rsplit(old, maxreplace))

Restituisce una copia della stringa s con tutte le occorrenze della sottostringa vecchie sostituite da nuove . Le prime ricorrenze maxreplace vengono sostituite.

e un esempio completo di questo in uso:

s = 'mississipi'
old = 'iss'
new = 'XXX'
maxreplace = 1

result = new.join(s.rsplit(old, maxreplace))
>>> result
'missXXXipi'

1
Bello! Utilizzato per rimuovere le virgole finali dalle linee: line = "".join(line.rsplit(",", 1))mantenendo successivamente lo spazio di riempimento.
nipote il

9

Basta invertire la stringa, sostituire la prima occorrenza e invertirla di nuovo:

mystr = "Remove last occurrence of a BAD word. This is a last BAD word."

removal = "BAD"
reverse_removal = removal[::-1]

replacement = "GOOD"
reverse_replacement = replacement[::-1]

newstr = mystr[::-1].replace(reverse_removal, reverse_replacement, 1)[::-1]
print ("mystr:", mystr)
print ("newstr:", newstr)

Produzione:

mystr: Remove last occurence of a BAD word. This is a last BAD word.
newstr: Remove last occurence of a BAD word. This is a last GOOD word.

5

Se sai che la "vecchia" stringa non contiene caratteri speciali, puoi farlo con una regex:

In [44]: s = '<div><div>Hello</div></div>'

In [45]: import re

In [46]: re.sub(r'(.*)</div>', r'\1</bad>', s)
Out[46]: '<div><div>Hello</div></bad>'

1

Ecco una soluzione ricorsiva al problema:

def rreplace(s, old, new, occurence = 1):

    if occurence == 0:
        return s

    left, found, right = s.rpartition(old)

    if found == "":
        return right
    else:
        return rreplace(left, old, new, occurence - 1) + new + right
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.