Małozachłanne RE ze spacją.

Jak przy pomocy re.match() w pythonie wyłowić miasto ze spacją z poniższej linijki przy założeniu, że kod pocztowy występuje zawsze, ale po mieście może wystąpić dowolna ilość wyrazów porozdzielanych spacjami?

'31-216 Olkusz ul. Manifestu Lipcowego 12/23 i może jeszcze coś'

Działa i wystarcza mi oczywiście wyrażenie

foo = re.match('(\d{2}-\d{3}) (.*)? .*', line)

ale zacząłem wczoraj z ciekawości zastanawiać się, jak do wyszukiwanego RE dołączyć spację [czyli z powyższego wyłowić ‚Olkusz ‚, nie ‚Olkusz’] i prawdę mówiąc odbiłem się od ściany. Any ideas?

9 thoughts on “Małozachłanne RE ze spacją.

  1. Wszystko poza spacją i spacja: [^␣]+␣:

    foo = re.match('(\d{2}-\d{3}) ([^ ]+ )?.*', line)
    

    (zakładając, że po mieście zawsze występuje spacja (albo miasto składa się z dwóch lub więcej słów 🙂 ))

    Polubienie

  2. @rozie ad 5: wiem, o tych przypadkach pomyślałem [jeszcze Piotrków Trybunalski ;)], ale w tym, co robię, nie ma to AŻ TAKIEGO znaczenia.

    Co do .* na końcu, faktycznie masz rację; w oryginale łapałem to do reszty nazwy w trzeci nawias, tutaj zapomniałem.

    Polubienie

  3. Po pierwsze odradzam dosłowne spacje w wyrażeniach regularnych. Osobiście wszędzie, gdzie spodziewam się spacji, piszę ‚\s+’, co łapie dowolną ilość dowolnych białych znaków oprócz ‚\n’. Dużo bardziej uniwersalne. Ale może to moje zboczenie człowieka, który wszystko trzyma w czytsym tekście i lubi mieć ładnie sformatowane spacjami.

    Po drugie zakładając, że każde słowo w nazwie miejsciowości zaczyna się wielką literą, możesz zrobić tak:

    foo = re.match(r'(\d{2}-\d{3})\s([A-Z]\w+)+\s+ul\..‚, line)

    Po trzecie w nazwie miejscowości czasem zdarzy się dywiz, więc też warto dodać.

    Po czwarte, jeżeli używasz tego wyrażenia wielokrotnie w ciągu działania skryptu, warto je skompilować:

    foo = re.compile(r'(\d{2}-\d{3})\s([A-Z][\w-]+)+\s+ul\..‚)
    foo.match(line)

    Po piąte ten kod, który podałeś nie powinien działać. Backslashe są znakami specjalnymi w łańcuchch tekstowych. Trzeba albo poprzedzać je drugim backslashem (‚\\’), albo oznaczyć łańcuch jako „raw string”, poprzedziając go literą r, jak powyżej.

    Po szóste, nie jest prawdą, że ‚.‚ na końcu nic nie wnosi. W tym konkretnym przypadku wnosi, ponieważ re.match() wymaga dokładnego dopasowania stringu do wyrażenia. Bez tego ‚.‚ na końcu nie zadziała.

    Polubienie

  4. @Świętomir: Co do \s zgoda (i miałem pisać, ale \ ze smartfona to masakra, poza tym, nie ten język, a chyba nie wszystko \s łapie). Za to nadużywasz plusów. \d{2}-\d{3})\s([A-Z][\w-]+)+ – to złapie z dywizem, ale już dwuczłonowych nie złapie. No i na Czechowice-Dziedzice wystarczy bez plusa na końcu. Skoro już polegasz na ul\. to znacznie prościej lecieć: \d{2}-\d{3}\s+(.*)ul\.

    I pewnie do wersji z łapaniem „separatorów”, czyli pl., al., ul. bym się skłaniał. Choć zależy czy lista zamknięta, czy nie. Jeśli userzy mają dowolność, to będzie lipa/trudniej. Zresztą wtedy też nie polegałbym na wielkiej literze na początku nazwy miejscowości…

    Nawiasem, jeśli to nie tylko Polska (ale tylko, bo kody pocztowe…), to wielka litera na początku nazwy miejscowości nie jest wymagana. 😉 Przykład(y) pozostawię jako zagadkę, jak nikt nie poda w ciągu paru dni, to napiszę.

    Polubienie

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s