2011-02-04 23 views
12

Estoy buscando la manera más rápida de reemplazar una gran cantidad de cadenas secundarias dentro de una cadena muy grande. Aquí hay dos ejemplos que he usado.Método más rápido de Python para buscar y reemplazar en una cadena grande

findall() se siente más simple y más elegante, pero lleva una cantidad de tiempo asombrosa.

finditer() se abre a través de un archivo grande, pero no estoy seguro de que este sea el camino correcto para hacerlo.

Aquí hay un código de muestra. Tenga en cuenta que el texto real que me interesa es una cadena única de alrededor de 10 MB de tamaño, y hay una gran diferencia en estos dos métodos.

import re 

def findall_replace(text, reg, rep): 
    for match in reg.findall(text): 
     output = text.replace(match, rep) 
    return output 

def finditer_replace(text, reg, rep): 
    cursor_pos = 0 
    output = '' 
    for match in reg.finditer(text): 
     output += "".join([text[cursor_pos:match.start(1)], rep]) 
     cursor_pos = match.end(1) 
    output += "".join([text[cursor_pos:]]) 
    return output 

reg = re.compile(r'(dog)') 
rep = 'cat' 
text = 'dog cat dog cat dog cat' 

finditer_replace(text, reg, rep) 

findall_replace(text, reg, rep) 

ACTUALIZACIÓN método Agregado re.sub a pruebas:

def sub_replace(reg, rep, text): 
    output = re.sub(reg, rep, text) 
    return output 

Resultados

re.sub() - 0: 00: 00,031000
finditer() - 0 : 00: 00.109000
findall() - 0: 01: 17.260000

+0

y el segundo uno es realmente mucho más rápido? Me parece extraño, deberían tomar aprox. al mismo tiempo. Y creo que ambas formas son correctas. –

+0

¿por qué no usas el submétodo de re? –

+1

Usar + = con cadenas es una operación O (n^2), en comparación con O (n) de compilar una lista y usar "" para unir. –

Respuesta

14

El método estándar es el uso de la incorporada en el

re.sub(reg, rep, text) 

Por cierto la razón de la diferencia de rendimiento entre las versiones es que cada uno de reemplazo en su primera versión hace que toda la cadena que se va a copiarse. Las copias son rápidas, pero cuando está copiando 10 MB de una vez, las copias serán lentas.

+0

Gracias. No usé re.sub() porque pensé que funcionaba de la misma manera que findall. Ejecuté mis pruebas nuevamente y re.sub es claramente el método más rápido. Los resultados han sido agregados a la pregunta. – cyrus

4

Usted puede, y creo que se debe, ya que sin duda es una función optimizada, utilice

re.sub(pattern, repl, string[, count, flags]) 

La razón por la que su findall_replace() función es larga es que en cada partido, un nuevo objeto de cadena se crea, como se verá por ejecutado el siguiente código:

ch = '''qskfg qmohb561687ipuygvnjoihi2576871987uuiazpoieiohoihnoipoioh 
opuihbavarfgvipauhbi277auhpuitchpanbiuhbvtaoi541987ujptoihbepoihvpoezi 
abtvar473727tta aat tvatbvatzeouithvbop772iezubiuvpzhbepuv454524522ueh''' 

import re 

def findall_replace(text, reg, rep): 
    for match in reg.findall(text): 
     text = text.replace(match, rep) 
     print id(text) 
    return text 

pat = re.compile('\d+') 
rep = 'AAAAAAA' 

print id(ch) 
print 
print findall_replace(ch, pat, rep) 

Tenga en cuenta que en este código substituí output = text.replace(match, rep) con text = text.replace(match, rep), de lo contrario sólo se sustituye la última ocurrencia.

finditer_replace() es largo por la misma razón que para findall_replace(): creación repetida de un objeto de cadena. Pero el primero usa un iterador re.finditer() mientras que el último se construye por sí mismo y es un objeto de lista, por lo que es más largo. Esa es la diferencia entre iterador y no iterador.

1

Por cierto, el código con findall_replace() no es seguro, puede devolver resultados unawaited:

ch = 'sea sun ABC-ABC-DEF bling ranch micABC-DEF fish' 

import re 

def findall_replace(text, reg, rep): 
    for gr in reg.findall(text): 
     text = text.replace(gr, rep) 
     print 'group==',gr 
     print 'text==',text 
    return '\nresult is : '+text 

pat = re.compile('ABC-DE') 
rep = 'DEFINITION' 

print 'ch==',ch 
print 
print findall_replace(ch, pat, rep) 

pantalla

ch== sea sun ABC-ABC-DEF bling ranch micABC-DEF fish 

group== ABC-DE 
text== sea sun ABC-DEFINITIONF bling ranch micDEFINITIONF fish 
group== ABC-DE 
text== sea sun DEFINITIONFINITIONF bling ranch micDEFINITIONF fish 

result is : sea sun DEFINITIONFINITIONF bling ranch micDEFINITIONF fish 
Cuestiones relacionadas