2009-06-02 12 views
6

W PHP masz preg_replace($patterns, $replacements, $string), gdzie możesz dokonać wszystkich zmian na raz, przekazując tablicę wzorców i zamienników.Czy możesz przekazać słownik podczas zamiany ciągów znaków w Pythonie?

Co to jest odpowiednik w Pythonie?

Zauważyłem, że ciąg i re funkcje replace() i sub() nie biorą słowniki ...

edytowane wyjaśnienia oparte na komentarz przez Rick: chodzi o to, aby mieć dict z kluczami, które należy podjąć jako wzorce wyrażenia regularnego, takie jak '\d+S' i (miejmy nadzieję) stałe wartości ciągów (miejmy nadzieję, w/o odsyłacze wsteczne). Teraz odpowiednio edytuję swoją odpowiedź (tj. Aby odpowiedzieć na faktyczne pytanie).

Odpowiedz

10

najbliżej jest chyba:

somere.sub(lambda m: replacements[m.group()], text) 

na przykład:

>>> za = re.compile('z\w') 
>>> za.sub(lambda m: dict(za='BLU', zo='BLA')[m.group()], 'fa za zo bu') 
'fa BLU BLA bu' 

z .get zamiast [] -indexing jeśli chcesz dostarczyć domyślne meczów, których brakuje w replacements.

Edycja: Rick naprawdę chce mieć dyktando z kluczami, które należy wziąć za wzorce regularnego wyrażania, takie jak '\d+S' i (mam nadzieję) wartościami stałych łańcuchów (miejmy nadzieję, że backreferences). Przepis Cookbook można zaadaptować do tego celu:

def dict_sub(d, text): 
    """ Replace in 'text' non-overlapping occurences of REs whose patterns are keys 
    in dictionary 'd' by corresponding values (which must be constant strings: may 
    have named backreferences but not numeric ones). The keys must not contain 
    anonymous matching-groups. 
    Returns the new string.""" 

    # Create a regular expression from the dictionary keys 
    regex = re.compile("|".join("(%s)" % k for k in d)) 
    # Facilitate lookup from group number to value 
    lookup = dict((i+1, v) for i, v in enumerate(d.itervalues())) 

    # For each match, find which group matched and expand its value 
    return regex.sub(lambda mo: mo.expand(lookup[mo.lastindex]), text) 

Przykład użycia:

d={'\d+S': 'wot', '\d+T': 'zap'} 
    t='And 23S, and 45T, and 66T but always 029S!' 
    print dict_sub(d, t) 

emituje:

And wot, and zap, and zap but always wot! 

Można uniknąć budowania lookup i po prostu użyć mo.expand(d.values()[mo.lastindex-1]), ale to może być odrobinę powolne, jeśli d jest bardzo duże i jest wiele dopasowań (przepraszam, nie dokładnie mierzyłem/porównywałem oba podejścia, więc to jest tylko przypuszczenie ;-).

+0

obsługuje tylko jeden regex, myślę, że można nie będzie łatwiejsze niż funkcja, którą złapałem z ActiveState, na wypadek gdybyś chciał zarówno zamienników, jak i wzorów. Czy możesz? –

+0

Aby wykonać kilka substytucji ciągów w jednym przebiegu, podoba mi się ten przepis, dlatego wybrałem go dla Cookbook Pythona, zobacz http://books.google.com/books?id=Q0s6Vgb98CQC&pg=PA38&dq=xavier+defrang&ei=k5okSvPbNILClQSk2LWvBw (Myślę, że dyskusja, którą dodaliśmy do Anny, dodała pewną wartość, ale jestem oczywiście stronnicza). Próbowałem odpowiedzieć bardziej bezpośrednio na dokładnie zadane pytanie - całkowicie ogólną RE i dany dyktat zastępowania. –

+0

Myślę, że oryginalne pytanie lepiej odpowiada przepisowi, ponieważ preg_replace w PHP akceptuje zarówno wiele wyrażeń regularnych, jak i zamienników. –

-2

To dosyć łatwo to zrobić:

replacements = dict(hello='goodbye', good='bad') 
s = "hello, good morning"; 
for old, new in replacements.items(): 
    s = s.replace(old, new) 

Znajdziesz tu wiele miejsc, w których funkcje PHP akceptują tablicę wartości i nie ma bezpośredniego odpowiednika Python, ale dużo łatwiej jest pracować z tablicami (listy) w Pythonie, więc jest to mniejszy problem.

+0

możesz chcieć użyć dict.iteritems zamiast dict.items, per PEP290 http://www.python.org/dev/peps/pep- 0290/# pętli-over-słownikach – NicDumZ

+5

Nie podoba mi się to. Funkcja dict.items() nie jest gwarantowana w żadnej określonej kolejności, więc wynikowy zamiennik jest nieprzewidywalny. Na przykład w twoim przykładzie, jeśli "hello" jest przetwarzane jako pierwsze, wynikowy ciąg to "badbye, bad morning"; inaczej, to "do widzenia, zły poranek". – Triptych

+0

@ Triptych: Nice catch. –

-1

Oto prosty sposób, za pomocą zmniejszenia

mynewstring=reduce(lambda a,(b,c): a.replace(b, c), mydict.items(), mystring) 
+0

To się nie powiedzie, jeśli mydict to '{'a': 'b', 'b': 'a'}' – Eric

+0

@Eric to cena, którą płacimy za bycie prostą. ten prosty sposób symuluje przykuty zastępstwa. –

+1

Proste rozwiązanie jest bezużyteczne, jeśli nie działa również – Eric

-2

można przekazać słownika zastępując ciąg w Pythonie. Rozważmy powyższym przykładzie:

replacement = {'hello' : 'goodbye', 'good' : 'bad' } 

trzeba napisać ciąg w tym formacie

s = "%(hello)s, %(good)s morning" 
changed_s = s%replacement 

wyjście changed_s będzie

"goodbye, bad morning" 
+1

-1: To nie jest zastępowanie ciągu, jego interpolacja ciągów. – Blair

Powiązane problemy