2011-02-04 12 views
12

Poszukuję najszybszego sposobu na zastąpienie dużej liczby pod-ciągów wewnątrz bardzo dużego ciągu. Oto dwa przykłady, których użyłem.Najszybsza metoda Pythona do wyszukiwania i zamiany na dużym łańcuchu

findall() Czuje się prostsze i bardziej eleganckie, ale zajmuje zdumiewającą ilość czasu.

finditer() lśni przez duży plik, ale nie jestem pewien, czy to właściwy sposób.

Oto przykładowy kod. Zwróć uwagę, że tekst, który mnie interesuje, jest pojedynczym łańcuchem o rozmiarze około 10 MB i istnieje ogromna różnica w tych dwóch metodach.

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) 

UPDATE Dodano re.sub metody badań:

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

Wyniki

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

+0

a drugi jest naprawdę dużo szybciej? Wydaje mi się dziwne, powinny one zająć około. o tym samym czasie. I myślę, że obie drogi są poprawne. –

+0

dlaczego nie używasz metody re's sub? –

+1

Używanie + = z ciągami jest operacją O (n^2), w porównaniu do O (n) budowania listy i używania "" do łączenia. –

Odpowiedz

14

Standardową metodą jest użycie wbudowanego

re.sub(reg, rep, text) 

Nawiasem mówiąc powodem różnicy pomiędzy wydajnością swoich wersjach jest to, że każda wymiana w swojej pierwszej wersji powoduje, że cały ciąg być recopied. Kopie są szybkie, ale gdy kopiujesz 10 MB za jednym razem, wystarczająca ilość kopii stanie się wolna.

+0

Dziękuję. Nie użyłem re.sub(), ponieważ myślałem, że działa w taki sam sposób jak findall. Znowu uruchomiłem testy, a re.sub jest zdecydowanie najszybszą metodą. Wyniki zostały dodane do pytania. – cyrus

4

Można, i myślę, że trzeba, bo to na pewno jest zoptymalizowana funkcja, użyj

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

powód dlaczego findall_replace() funkcja jest długa jest to, że w każdym meczu, nowy obiekt ciąg jest tworzony, jak widać przez zawartej następującego kodu:

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) 

pamiętać, że w tym kodzie Wymieniłem output = text.replace(match, rep) z text = text.replace(match, rep), inaczej tylko ostatnie wystąpienie otrzymuje.

finditer_replace() jest długi z tego samego powodu, co dla findall_replace(): wielokrotne tworzenie obiektu typu string. Ale ten pierwszy używa iteratora re.finditer(), podczas gdy ten drugi konstruuje obiekt listy, więc jest dłuższy. To jest różnica między iteratorem a nie-iteratorem.

1

Nawiasem mówiąc, Twój kod z findall_replace() nie jest bezpieczny, można go zwrócić wyników 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) 

wyświetlacz

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 
Powiązane problemy