Zanurkuj w Pythonie/Analiza przypadku: Przetwarzanie numerów telefonów: Różnice pomiędzy wersjami
Usunięta treść Dodana treść
poprawki |
poprawki |
||
Linia 27:
{{samp|('800', '555', '1212')}}
>>> phonePattern.search('800-555-1212-1234') #(3)
>>>
# Zawsze odczytujemy wyrażenie regularne od lewej do prawej. Tutaj dopasowujemy początek łańcucha znaków, potem <tt>(\d{3})</tt>. Co to takiego te <tt>(\d{3})</tt>? <tt>{3}</tt> oznacza "dopasuj dokładnie 3 wystąpienia" (jest to wariacja składni <tt>{n, m}</tt>). <tt>\d</tt> oznacza "jakakolwiek cyfra" (od 0 do 9). Umieszczenie ich w nawiasach oznacza "dopasuj dokładnie 3 cyfry, i zapamiętaj je jako grupę, o którą można zapytać później". Następnie mamy dopasować myślnik. Dalej dopasuj kolejną grupę dokładnie trzech cyfr, a następnie kolejny myślnik, i ostatnią grupę tym razem czterech cyfr. Na koniec dopasuje koniec łańcucha znaków.
Linia 42 ⟶ 43:
>>>
>>> phonePattern.search('800-555-1212') #(4)
>>>
# To wyrażenie regularne jest praktycznie identyczne z wcześniejszym. Tak jak wcześniej, dopasowujemy początek łańcucha, potem zapamiętywaną grupę trzech cyfr, myślnik, zapamiętywaną grupę trzech cyfr, myślnik i zapamiętywaną grupę czterech cyfr. Nową częścią jest kolejny myślnik i zapamiętywana grupa jednej lub więcej cyfr. Na końcu jak w poprzednim przykładzie dopasowujemy koniec łańcucha.
Linia 51 ⟶ 53:
Następny przykład pokazuje wyrażenie regularne, które obsługuje różne separatory między częściami numeru telefonu.
|7.12 |tekst=
>>> phonePattern = re.compile(r'^(\d{3})\D+(\d{3})\D+(\d{4})\D+(\d+)$') #(1)
>>> phonePattern.search('800 555 1212 1234').groups() #(2)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800-555-1212-1234').groups() #(3)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('80055512121234') #(4)
>>>
>>> phonePattern.search('800-555-1212') #(5)
>>>
# Teraz dopasowujemy początek łańcucha, grupę trzech cyfr, potem <tt>\D+</tt>... zaraz, zaraz, co to jest? <tt>\D</tt> dopasowuje dowolny znak, który nie jest cyfrą, a + oznacza "jeden lub więcej". Więc <tt>\D+</tt> dopasowuje jeden lub więcej znaków nie będących cyfrą. Korzystamy z niego, aby dopasować różne separatory, nie tylko myślniki.
# Korzystanie z <tt>\D+</tt> zamiast z <tt>-</tt> pozwala na dopasowywanie numerów telefonów ze spacjami w roli separatora części.
# Oczywiście myślniki też działają.
# Niestety, to dalej nie jest ostateczna wersja, ponieważ nie obsługuje ona braku jakichkolwiek separatorów.
# No i dalej nie rozwiązany pozostał problem możliwości braku numeru wewnętrznego. Mamy więc dwa problemy do rozwiązania, ale w obu przypadkach rozwiążemy problem tą samą techniką.
}}
Następny przykład pokazuje wyrażenie regularne pasujące także do numeru bez separatorów.
|7.13 |tekst=
>>> phonePattern = re.compile(r'^(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') #(1)
>>> phonePattern.search('80055512121234').groups() #(2)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800.555.1212 x1234').groups() #(3)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800-555-1212').groups() #(4)
{{samp|<nowiki>('800', '555', '1212', '')</nowiki>}}
>>> phonePattern.search('(800)5551212 x1234') #(5)
>>>
# Jedyna zmiana jakiej dokonaliśmy od ostatniego kroku to zamiana wszystkich <tt>+</tt> na <tt>*</tt>. Zamiast <tt>\D+</tt> pomiędzy częściami numeru telefonu dopasowujemy teraz <tt>\D*</tt>. Pamiętasz, że <tt>+</tt> oznacza "1 lub więcej"? <tt>*</tt> oznacza "0 lub więcej". Tak więc teraz jesteśmy w stanie przetworzyć numer nawet bez separatorów.
# Nareszcie działa! Dlaczego? Dopasowany został początek łańcucha, grupa 3 cyfr (800), potem zero znaków nienumerycznych, potem znowu zapamiętywana grupa 3 cyfr (555), znowu zero znaków nienumerycznych, zapamiętywana grupa 4 cyfr (1212), zero znaków nienumerycznych, numer wewnętrzny (1234) i nareszcie koniec łańcucha.
# Inne odmiany też działają np. numer rozdzielony kropkami ze spacją i <tt>x</tt>-em przed numerem wewnętrznym.
# Wreszcie udało się też rozwiązać problem z brakiem numeru wewnętrznego. Tak czy siak <tt>groups()</tt> zwraca nam
#
}}
Następny przykład pokazuje jak sobie radzić ze znakami wiodącymi w numerach telefonów.
|7.14 |tekst=
>>> phonePattern = re.compile(r'^\D*(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') #(1)
>>> phonePattern.search('(800)5551212 ext. 1234').groups() #(2)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800-555-1212').groups() #(3)
{{samp|<nowiki>('800', '555', '1212', '')</nowiki>}}
>>> phonePattern.search('work 1-(800) 555.1212 #1234') #(4)
>>>
# Wzorzec w tym przykładzie jest taki sam jak w poprzednim, z wyjątkiem tego, że teraz na początku łańcucha dopasowujemy <tt>\D*</tt> przed pierwszą zapamiętywaną grupą (numerem kierunkowym). Zauważ że tych znaków nie zapamiętujemy (nie są one w nawiasie). Jeśli je napotkamy, to ignorujemy je i przechodzimy do numeru kierunkowego.
# Teraz udało się przetworzyć numer telefonu z nawiasem otwierającym na początku. (Zamykający był już wcześniej obsługiwany; był traktowany jako nienumeryczny znak pasujący do teraz drugiego <tt>\D*</tt>.)
# Tak na wszelki wypadek sprawdzamy czy nie popsuliśmy czegoś. Jako, że początkowy znak jest całkowicie opcjonalny, następuje dopasowanie w dokładnie taki sam sposób jak w poprzednim przykładzie.
# W tym miejscu wyrażenia regularne sprawiają, że chce się człowiekowi rozbić bardzo dużym młotem monitor. Dlaczego to nie pasuje? Wszystko za sprawą 1 przed numerem kierunkowym (numer kierunkowy USA), a przecież przyjęliśmy, że na początku mogą być tylko nienumeryczne znaki. Ech...
}}
Cofnijmy się na chwilę. Jak
'''Przykład 7.15. Numerze telefonu, znajdę cię gdziekolwiek jesteś!'''▼
{{Python/Przykład
|tekst=
>>> phonePattern = re.compile(r'(\d{3})\D*(\d{3})\D*(\d{4})\D*(\d*)$') #(1)
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() #(2)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800-555-1212') #(3)
{{samp|<nowiki>('800', '555', '1212', '')</nowiki>}}
>>> phonePattern.search('80055512121234') #(4)
{{samp|('800', '555', '1212', '1234')}}
# Zauważ, że brakuje <tt>^</tt> w tym wyrażeniu regularnym, Teraz już nie dopasowujemy początku łańcucha, bo przecież nikt nie powiedział, że wyrażenie musi pasować do całego łańcucha, a nie do fragmentu. Mechanizm wyrażeń regularnych sam zadba o namierzenie miejsca do którego ono pasuje (o ile w ogóle).
# Teraz nareszcie pasuje numer ze znakami na początku (w tym cyframi) i dowolnymi, jakimikolwiek separatorami w środku.
# Na wszelki wypadek sprawdzamy i to. Działa!
# To też działa.
}}
Póki jeszcze rozumiemy to co napisaliśmy, rozpiszmy to jako rozwlekłe wyrażenie regularne, żeby nie zapomnieć, co jest co i dlaczego.
|7.16 |tekst=
# nie dopasowuj początku łańcucha, numer może się zacząć gdziekolwiek
(\d{3}) # numer kierunkowy - 3 cyfry (np. '800')
Linia 138 ⟶ 150:
(\d*) # numer wewnętrzny jest opcjonalny i może mieć dowolną długość
$ # koniec łańcucha
''', re.VERBOSE)</nowiki>
>>> phonePattern.search('work 1-(800) 555.1212 #1234').groups() #(1)
{{samp|('800', '555', '1212', '1234')}}
>>> phonePattern.search('800-555-1212') #(2)
{{samp|<nowiki>('800', '555', '1212', '')</nowiki>}}</nowiki>
# Pomijając fakt, że jest ono podzielone na wiele linii, to wyrażenie jest dokładnie takie samo jak po ostatnim kroku, więc nie jest niespodzianką, że dalej działa jak powinno.
# Jeszcze jedna próba. Tak, działa! Skończone!
}}
<noinclude>
{{Nawigacja|Zanurkuj w Pythonie|
|