2013-03-02 5 views
20

Mogę użyć tego kodu poniżej, aby utworzyć nowy plik z zamiennikiem a z aa za pomocą wyrażeń regularnych.Jak mogę wykonać wiele podstawień za pomocą wyrażeń regularnych w pythonie?

import re 

with open("notes.txt") as text: 
    new_text = re.sub("a", "aa", text.read()) 
    with open("notes2.txt", "w") as result: 
     result.write(new_text) 

Zastanawiałem się, czy muszę korzystać z tej linii, new_text = re.sub("a", "aa", text.read()), wiele razy, ale zastąpić ciąg dla innych listów, które chcę zmienić, aby zmienić więcej niż jedną literę w moim tekście?

Oznacza to, że tak a ->aa, b ->bb i c ->cc.

Muszę napisać tę linijkę dla wszystkich liter, które chcę zmienić, lub istnieje łatwiejszy sposób. Być może stworzyć "słownik" tłumaczeń. Czy powinienem umieścić te litery w tablicy? Nie wiem, jak do nich zadzwonić, jeśli to zrobię.

Odpowiedz

27

Odpowiedź zaproponowana przez @nhahtdh jest poprawna, ale ja twierdzę, że jest mniej pytonowa niż przykład kanoniczny, który używa mniej kodu nieprzezroczystego niż jego regex manipuluje i wykorzystuje wbudowane struktury danych Pythona i funkcję anonimowej funkcji.

Słownik tłumaczeń ma sens w tym kontekście. W rzeczywistości, to w jaki sposób Python Cookbook robi, jak pokazano w poniższym przykładzie (skopiowany z ActiveState http://code.activestate.com/recipes/81330-single-pass-multiple-replace/)

import re 

def multiple_replace(dict, text): 
    # Create a regular expression from the dictionary keys 
    regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys()))) 

    # For each match, look-up corresponding value in dictionary 
    return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) 

if __name__ == "__main__": 

    text = "Larry Wall is the creator of Perl" 

    dict = { 
    "Larry Wall" : "Guido van Rossum", 
    "creator" : "Benevolent Dictator for Life", 
    "Perl" : "Python", 
    } 

    print multiple_replace(dict, text) 

Tak więc w Twoim przypadku, można wykonać dict trans = {"a": "aa", "b": "bb"} a następnie przekazać go do multiple_replace wraz z tekstem chcesz przetłumaczyć. Zasadniczo, cała ta funkcja polega na utworzeniu jednego dużego wyrażenia zawierającego wszystkie wyrażenia regularne do przetłumaczenia, a następnie, po znalezieniu, przesłaniu funkcji lambda do regex.sub w celu wykonania wyszukiwania słownika tłumaczeń.

Można użyć tej funkcji podczas czytania z pliku, na przykład:

with open("notes.txt") as text: 
    new_text = multiple_replace(replacements, text.read()) 
with open("notes2.txt", "w") as result: 
    result.write(new_text) 

mam faktycznie używane dokładnie tę metodę produkcji, w przypadku, gdy musiałem tłumaczyć miesięcy w roku od Czeski na angielski dla zadania skrobania stron internetowych.

Jak podkreślił @nhahtdh, jedną z wad tej metody jest to, że nie jest ona wolna od przedrostków: klucze słownikowe będące przedrostkami innych kluczy słownika powodują przerwanie metody.

+0

Wow, dzięki, prawie to, czego szukałem. Mam jeszcze jedno podstawowe pytanie: jak zignorować wielkie litery? Więc gdybym miał A i chciałem to przetłumaczyć na aa bez dodawania go do słownika. – Euridice01

+0

@ Euridice01: Jeśli chcesz zignorować wielkość liter, podaj flagę 're.I' w' re.compile'. – nhahtdh

+0

Twoje obecne rozwiązanie nie jest jeszcze skonfigurowane do użycia w przypadku, gdy istnieje para wyrazów, z których jeden jest przedrostkiem drugiego. Kolejność pojawiania się w materii naprzemiennej. Myślę, że przynajmniej powinieneś oświadczyć to założenie. – nhahtdh

12

Można użyć grupę i wstecznych przechwytywania:

re.sub(r"([characters])", r"\1\1", text.read()) 

znaków umieścić, że chcesz podwoić między []. Dla przypadku małych liter a, b, c:

re.sub(r"([abc])", r"\1\1", text.read()) 

w ciągu zastępowania, można odwołać się do tego, co w parze z grupy przechwytywania () z \n notacji gdzie n pewne pozytywny całkowita (0 wyłączone) . \1 odnosi się do pierwszej grupy przechwytującej. Istnieje kolejna notacja \g<n>, gdzie n może być dowolną nieujemną liczbą całkowitą (0 dozwolone); \g<0> będzie odnosić się do całego tekstu dopasowanego przez wyrażenie.


Jeśli chcesz podwoić wszystkie znaki z wyjątkiem nowej linii:

re.sub(r"(.)", r"\1\1", text.read()) 

Jeśli chcesz podwoić wszystkie znaki (nowa linia dołączonych):

re.sub(r"(.)", r"\1\1", text.read(), 0, re.S) 
1

Korzystanie wskazówek z how to make a 'stringy' class możemy uczynić obiekt identyczny z ciągiem, ale za dodatkową sub metody:

import re 
class Substitutable(str): 
    def __new__(cls, *args, **kwargs): 
    newobj = str.__new__(cls, *args, **kwargs) 
    newobj.sub = lambda fro,to: Substitutable(re.sub(fro, to, newobj)) 
    return newobj 

To pozwala na użycie wzorca Builder, który wygląda ładniej, ale działa tylko na pre - określona liczba substytucji. Jeśli używasz go w pętli, nie ma sensu tworzyć dodatkowej klasy. Na przykład.

>>> h = Substitutable('horse') 
>>> h 
'horse' 
>>> h.sub('h', 'f') 
'forse' 
>>> h.sub('h', 'f').sub('f','h') 
'horse' 
0

I stwierdzono, że miał zmodyfikować kod Emmetta J. Butlera przez zmianę funkcji lambda użyciu myDict.get (mo.group (1) mo.group (1)). Oryginalny kod nie działał dla mnie; używanie funkcji myDict.get() zapewnia także korzyść wartości domyślnej, jeśli klucz nie zostanie znaleziony.

OIDNameContraction = { 
           'Fucntion':'Func', 
           'operated':'Operated', 
           'Asist':'Assist', 
           'Detection':'Det', 
           'Control':'Ctrl', 
           'Function':'Func' 
} 

replacementDictRegex = re.compile("(%s)" % "|".join(map(re.escape, OIDNameContraction.keys()))) 

oidDescriptionStr = replacementDictRegex.sub(lambda mo:OIDNameContraction.get(mo.group(1),mo.group(1)), oidDescriptionStr) 
Powiązane problemy