python string replace substring

python - Reemplazar enésima aparición de subcadena en cadena



string replace (7)

He modificado la respuesta de @ aleskva para trabajar mejor con expresiones regulares y comodines:

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)

Esto le da a abdsahd15jhdasjk124ndjaksnd124ndjkas . Tenga en cuenta el uso de ? hacer que la consulta no sea codiciosa.

Me doy cuenta de que la pregunta establece explícitamente que no querían usar expresiones regulares, sin embargo, puede ser útil poder usar comodines de manera clara (de ahí mi respuesta).

Quiero reemplazar la enésima aparición de una subcadena en una cadena.

Tiene que haber algo equivalente a lo que QUIERO hacer, que es

mystring.replace("substring", 2nd)

¿Cuál es la forma más simple y más pitónica de lograr esto?

¿Por qué no duplicar ? No quiero usar expresiones regulares para este enfoque y la mayoría de las respuestas a preguntas similares que encontré son solo la eliminación de expresiones regulares o una función realmente compleja. Realmente quiero una solución lo más simple posible y no regex.


La última respuesta es casi perfecta, solo una corrección:

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

La cadena posterior debe almacenarse en esta variable nuevamente después del reemplazo. ¡Gracias por la gran solución!


Puede usar un ciclo while con str.find para encontrar la enésima ocurrencia si existe y usar esa posición para crear la nueva cadena:

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

Ejemplo:

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


Se me ocurrió lo siguiente, que considera también las opciones para reemplazar todas las ocurrencias de cadenas ''antiguas'' a la izquierda o a la derecha. Naturalmente, no hay ninguna opción para reemplazar todas las ocurrencias, ya que el reemplazo estándar de str funciona perfectamente.

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)


Tenía una necesidad similar, es decir, encontrar las IP en los registros y reemplazar solo el campo src IP o dst IP selectivamente. Así es como lo logré de manera pitónica;

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)


Utilizo una función simple, que enumera todas las ocurrencias, selecciona la enésima posición y la usa para dividir la cadena original en dos subcadenas. Luego reemplaza la primera aparición en la segunda subcadena y une las subcadenas nuevamente en la nueva cadena:

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

Para estas variables:

string = ''ababababababababab'' sub = ''ab'' wanted = ''CD'' n = 5

salidas:

ababababCDabababab

Notas:

La variable where es en realidad una lista de posiciones de coincidencias, donde se selecciona la enésima. Pero el índice de elementos de lista generalmente comienza con 0 , no con 1 . Por lo tanto, hay un índice n-1 n variable es la enésima subcadena real. Mi ejemplo encuentra la quinta cadena. Si usa n index y desea encontrar la quinta posición, necesitará que n sea 4 . El que usas generalmente depende de la función, que genera nuestro n .

Esta debería ser la forma más simple, pero tal vez no sea la forma más pitónica, porque la construcción de variables necesita importar re biblioteca. Quizás alguien encuentre aún más forma pitónica.

Fuentes y algunos enlaces además:


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