Ich möchte das n-te Vorkommen eines Teilstrings in einem String ersetzen.
Es muss etwas Äquivalentes zu dem geben, was ich tun möchte
mystring.replace("substring", 2nd)
Was ist der einfachste und pythonischste Weg, um dies zu erreichen?
Warum nicht duplizieren: Ich möchte Regex nicht für diesen Ansatz verwenden, und die meisten Antworten auf ähnliche Fragen, die ich gefunden habe, sind nur Regex-Stripping oder eine wirklich komplexe Funktion. Ich möchte wirklich so einfach wie möglich und keine Regex-Lösung.
Ich verwende eine einfache Funktion, die alle Vorkommen auflistet, die n-te Position des Benutzers auswählt und die ursprüngliche Zeichenfolge in zwei Teilstrings aufteilt. Dann ersetzt es das erste Vorkommen in der zweiten Teilzeichenfolge und fügt die Teilzeichenfolgen wieder in die neue Zeichenfolge ein:
import re
def replacenth(string, sub, wanted, n)
where = [m.start() for m in re.finditer(sub, string)][n-1]
before = string[:where]
after = string[where:]
after = after.replace(sub, wanted, 1)
newString = before + after
print newString
Für diese Variablen:
string = 'ababababababababab'
sub = 'ab'
wanted = 'CD'
n = 5
ausgänge:
ababababCDabababab
Anmerkungen:
Die Variable
where
ist tatsächlich eine Liste der Übereinstimmungspositionen, an der Sie die n-te Position abrufen. Der Listenelementindex beginnt jedoch normalerweise mit0
, nicht mit1
. Daher gibt es einenn-1
-Index undn
Variable ist der eigentliche n-te Teilstring. Mein Beispiel findet die 5. Saite. Wenn Sien
index verwenden und die fünfte Stelle suchen möchten, müssen Sien
als4
angeben. Was Sie verwenden, hängt in der Regel von der Funktion ab, die unseren
generiert.Dies sollte der einfachste Weg sein, aber es ist vielleicht nicht der pythonischste Weg, da für die Konstruktion der Variablen
where
die Bibliothekre
importiert werden muss. Vielleicht findet jemand noch mehr Pythonic-Weg.Quellen und einige Links dazu:
where
construction: Alle Vorkommen eines Teilstrings in Python suchen- zeichenfolgenaufteilung: https://www.daniweb.com/programming/software-development/threads/452362/replace-nth-occurrence-of-any-sub-string-in-a-string
- ähnliche Frage: Finden Sie das n-te Vorkommen eines Teilstrings in einem String
Sie können eine while-Schleife mit str.find
verwenden, um das n-te Vorkommen zu finden, falls vorhanden, und diese Position zum Erstellen der neuen Zeichenfolge verwenden:
def nth_repl(s, sub, repl, nth):
find = s.find(sub)
# if find is not p1 we have found at least one match for the substring
i = find != -1
# loop util we find the nth or we find no match
while find != -1 and i != nth:
# find + 1 means we start at the last match start index + 1
find = s.find(sub, find + 1)
i += 1
# if i is equal to nth we found nth matches so replace
if i == nth:
return s[:find]+repl+s[find + len(sub):]
return s
Beispiel:
In [14]: s = "foobarfoofoobarbar"
In [15]: nth_repl(s, "bar","replaced",3)
Out[15]: 'foobarfoofoobarreplaced'
In [16]: nth_repl(s, "foo","replaced",3)
Out[16]: 'foobarfooreplacedbarbar'
In [17]: nth_repl(s, "foo","replaced",5)
Out[17]: 'foobarfoofoobarbar'
Ich habe mir das folgende vorgestellt, das auch Optionen in Betracht zieht, um alle 'alten' String-Vorkommen nach links oder nach rechts zu ersetzen. Natürlich gibt es keine Option, um alle Vorkommen zu ersetzen, da str.replace standardmäßig perfekt funktioniert.
def nth_replace(string, old, new, n=1, option='only nth'):
"""
This function replaces occurrences of string 'old' with string 'new'.
There are three types of replacement of string 'old':
1) 'only nth' replaces only nth occurrence (default).
2) 'all left' replaces nth occurrence and all occurrences to the left.
3) 'all right' replaces nth occurrence and all occurrences to the right.
"""
if option == 'only nth':
left_join = old
right_join = old
Elif option == 'all left':
left_join = new
right_join = old
Elif option == 'all right':
left_join = old
right_join = new
else:
print("Invalid option. Please choose from: 'only nth' (default), 'all left' or 'all right'")
return None
groups = string.split(old)
nth_split = [left_join.join(groups[:n]), right_join.join(groups[n:])]
return new.join(nth_split)
Die letzte Antwort ist nahezu perfekt - nur eine Korrektur:
def replacenth(string, sub, wanted, n):
where = [m.start() for m in re.finditer(sub, string)][n - 1]
before = string[:where]
after = string[where:]
after = after.replace(sub, wanted)
newString = before + after
return newString
Die Nachfolge muss nach dem Ersetzen wieder in dieser Variablen gespeichert werden. Vielen Dank für die großartige Lösung!
def replace_nth_occurance(some_str, original, replacement, n):
""" Replace nth occurance of a string with another string
"""
some_str.replace(original, replacement, n)
for i in range(n):
some_str.replace(replacement, original, i)
return some_str
Ich hatte ein ähnliches Bedürfnis, d. H. Die IPs in Protokollen zu finden und nur src IP oder dst IP Feld selektiv zu ersetzen. So habe ich Pythonic erreicht;
import re
mystr = '203.23.48.0 DENIED 302 449 800 1.1 302 http d.flashresultats.fr 10.111.103.202 GET GET - 188.92.40.78 '
src = '1.1.1.1'
replace_nth = lambda mystr, pattern, sub, n: re.sub(re.findall(pattern, mystr)[n - 1], sub, mystr)
result = replace_nth(mystr, '\S*\d+\.\d+\.\d+\.\d+\S*', src, 2)
print(result)
Ich habe die Antwort von @aleskva überarbeitet, um besser mit Regex und Wildcards arbeiten zu können:
import re
def replacenth(string, sub, wanted, n):
pattern = re.compile(sub)
where = [m for m in pattern.finditer(string)][n-1]
before = string[:where.start()]
after = string[where.end():]
newString = before + wanted + after
return newString
replacenth('abdsahd124njhdasjk124ndjaksnd124ndjkas', '1.*?n', '15', 1)
Das gibt abdsahd15jhdasjk124ndjaksnd124ndjkas
. Beachten Sie die Verwendung von ?
, um die Abfrage nicht gierig zu machen.
Mir ist klar, dass die Frage ausdrücklich besagt, dass sie Regex nicht verwenden wollten, aber es kann nützlich sein, Wildcards in klarer Form zu verwenden (daher meine Antwort).