rreplace - Jak zamienić ostatnie wystąpienie wyrażenia w ciągu?


139

Czy w Pythonie istnieje szybki sposób na zastąpienie ciągów, ale zamiast zaczynać od początku, jak to się replacedzieje, zaczynając od końca? Na przykład:

>>> 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
Dobre pytanie, sądząc po skomplikowanych rozwiązaniach tak prostego problemu.
— Justin Ardini

3
W poniższych odpowiedziach znajduje się elegancka jedna linijka, której dodanie do tego pytania zajęło 9 lat (!), Po prostu przewiń w dół, aby ją znaleźć.
— John D

Odpowiedzi:


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
Bardzo dobrze! W nienaukowym benchmarku polegającym na zamianie ostatniego wystąpienia wyrażenia w typowym ciągu w moim programie (> 500 znaków), Twoje rozwiązanie było trzy razy szybsze niż rozwiązanie Alexa i cztery razy szybsze niż rozwiązanie Marka. Dziękuję wszystkim za odpowiedzi!
— Barthelemy

2
Dzięki, działa. .replaceMetoda ta trzecia opcjonalny argument „licznik”, który informuje go zastąpić n pierwszych zdarzeń. Czy nie byłoby to intuicyjne, gdyby wymagało to -1, ale niestety nie, więc potrzebujemy Twojego rozwiązania.
— kardamon

17

Nie zamierzam udawać, że jest to najefektywniejszy sposób, ale jest to prosty sposób. Odwraca wszystkie odnośne ciągi, wykonuje zwykłą zamianę, używając str.replaceodwróconych ciągów, a następnie odwraca wynik z powrotem we właściwą stronę:

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

Oto jedna linijka:

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

Zwraca kopię łańcucha s ze wszystkimi wystąpieniami podłańcucha starego zamienionego na nowy . Pierwsze wystąpienia maxreplace są zastępowane.

i pełny przykład tego w użyciu:

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

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

1
Miły! Użył go do usunięcia końcowych przecinków z wierszy: line = "".join(line.rsplit(",", 1))zachowując później spację dopełnienia.
— wnuczka

9

Po prostu odwróć ciąg, zamień pierwsze wystąpienie i odwróć je ponownie:

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)

Wynik:

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

Jeśli wiesz, że „stary” ciąg nie zawiera żadnych znaków specjalnych, możesz to zrobić za pomocą wyrażenia regularnego:

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

Oto rekurencyjne rozwiązanie problemu:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.