python
  • regex
  • 2012-12-06 11 views 27 likes 
    27

    Robię trochę normalizacji tekstu za pomocą python i wyrażeń regularnych. Chciałbym zastąpić wszystkie "u'lub" U "tobą". Oto co zrobiłem do tej pory:Python re.sub(): jak zastąpić wszystkie "u" lub "U" z "ty"

    import re 
    text = 'how are u? umberella u! u. U. [email protected] U# u ' 
    print re.sub (' [u|U][s,.,?,!,W,#,@ (^a-zA-Z)]', ' you ', text) 
    

    Wyjście pojawia się:

    how are you you berella you you you you you you 
    

    Jak widać problem jest, że „parasolki” zmienia się na „berella”. Chcę też zachować postać, która pojawia się po "u". Na przykład chcę "u!" zmienić na "ty!". Czy ktoś może mi powiedzieć, co robię źle i jaki jest najlepszy sposób napisania wyrażenia regularnego?

    Odpowiedz

    48

    Po pierwsze, dlaczego Twoje rozwiązanie nie działa. Wymieszać wiele pojęć. Głównie character class z innymi. W pierwszej klasie znaków używasz |, która pochodzi od alternation. W klasach postaci nie potrzebujesz rury. Wystarczy wymienić wszystkie znaki (i zakresy znaków) ma:

    [Uu] 
    

    Albo po prostu napisać u jeśli używasz bez uwzględniania wielkości liter modyfikatora. Jeśli napiszesz tam rurę, klasa postaci będzie faktycznie dopasowywać rury w twoim temacie.

    Teraz w drugiej klasie postaci używamy przecinka do oddzielania znaków z jakiegoś dziwnego powodu. Nie ma w tym nic poza przecinkami do postaci, które można dopasować. s i W prawdopodobnie mają być wbudowanymi klasami znaków. Więc uciec z nich! W przeciwnym razie po prostu pasują do literału s i literalnie W. Ale wtedy \W zawiera już wszystko, co tam wymieniłeś, więc wystarczyłby sam (bez nawiasów kwadratowych). I ostatnia część (^a-zA-Z) również nie działa, ponieważ po prostu będzie zawierała ^, (, ) i wszystkie litery do klasy postaci. Składnia negacji działa tylko dla całych klas znaków, takich jak [^a-zA-Z].

    To, czego naprawdę chcesz, to stwierdzenie, że nie ma litery przed lub po u. Możesz użyć do tego lookarounds. Zaletą jest to, że nie zostaną one uwzględnione w meczu, a tym samym nie zostaną usunięte:

    r'(?<![a-zA-Z])[uU](?![a-zA-Z])' 
    

    Zauważ, że użyłem surowy ciąg. Zwykle jest to dobra praktyka dla wyrażeń regularnych, aby uniknąć problemów z sekwencjami ucieczkowymi.

    To są negatywne spojrzenia, które sprawiają, że nie ma litery przed ani po u. Jest to ważna różnica w stwierdzeniu, że w pobliżu jest znak inny niż litera (podobny do tego, co zrobiłeś), ponieważ to drugie podejście nie będzie działać na początku ani na końcu ciągu znaków.

    Oczywiście można usunąć spacje wokół numeru you z ciągu zastępczego.

    Jeśli nie chcesz zastąpić u że są obok cyfr, można łatwo zawierać cyfry do klas postaci:

    r'(?<![a-zA-Z0-9])[uU](?![a-zA-Z0-9])' 
    

    a jeśli z jakiegoś powodu sąsiednia podkreślenia również dyskwalifikacji swoją u do wymiany możesz również dołączyć. Ale wtedy klasa znaków pokrywa się z wbudowanego \w:

    r'(?<!\w)[uU](?!\w)' 
    

    Który jest w tym przypadku równoznaczne EarlGray na r'\b[uU]\b'.

    Jak wspomniano powyżej, można skrócić wszystkie z nich, używając modyfikatora niewrażliwego na wielkość liter. Biorąc pierwszy wyraz jako przykład:

    re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.I) 
    

    lub

    re.sub(r'(?<![a-z])u(?![a-z])', 'you', text, flags=re.IGNORECASE) 
    

    w zależności od preferencji.

    Proponuję przeczytać kilka razy w tutorialu, który kilka razy łączyłem w tej odpowiedzi. Wyjaśnienia są bardzo obszerne i powinny dać ci dobry początek w wyrażeniach regularnych, które prawdopodobnie wcześniej czy później napotkasz.

    +2

    Twoja odpowiedź była znakomita. Dzięki! – user823743

    +0

    to jest interesująca ogólna technika, ale wolałbym użyć \ b, aby dopasować słowo break –

    +2

    @Sam Chciałem tylko upewnić się, że implikacje użycia '\ b' były jasne (w szczególności, że cyfry i podkreślenia są w cenie). –

    11

    użyć specjalnego charakter \b, który dopasowuje pusty łańcuch na początku lub na końcu wyrazu:

    print re.sub(r'\b[uU]\b', 'you', text) 
    

    przestrzenie nie są niezawodne rozwiązanie, ponieważ istnieje również wiele innych znaków interpunkcyjnych, więc abstrakcyjny charakter \b został wymyślony, aby wskazać początek lub koniec słowa.

    +2

    wyjątkiem tego, że ' '\ b'' jest taka sama jak'' \ x08''. musisz uciec ('' \\ b'' lub 'r '\ b'')! – mata

    +1

    To jest wyjście twojego kodu na "tekst", jak zdefiniowałem w kodzie: jak się masz? umberella u! u. U. U @ U # u Więc żadne z u nie zostały zmienione dla ciebie. – user823743

    +1

    @ user823743 Tak, zapomniałem 'r' przed moim regularnym wyrażeniem, tak jak zostało to zredagowane przez Wooble (dzięki!). –

    0

    Innym możliwym rozwiązaniem wymyśliłem było:

    re.sub(r'([uU]+(.)?\s)',' you ', text) 
    
    Powiązane problemy