Numery telefonów

Gdy programujemy skrypty związaną z contact center, czy innymi aplikacjami z rodziny telefonii IP, bardzo szybko spotkamy się zadaniami, w których musimy przetworzyć numery telefonów. Z produktów związanych z telefonią numer uzyskujemy zazwyczaj w formacie E.164. Dane zapisane w różnego rodzaju bazach danych czy plikach tekstowych, które nasze skrypty będą przetwarzać, prawie na pewno nie będą zawsze zgodne z tym międzynarodowym standardem. Z takim problemem miałem do czynienia niedawno, gdy w projekcie dla mojego klienta pisałem dodatkowe skrypty do Amazon Connect, czyli call center w chmurze Amazona. W operowaniu różnego rodzaju formatami numerów telefonicznych pomogła mi biblioteka phonenumbers.

Numer telefonu zapisany na wiele sposobów

W tego typu projektach spotkamy się zazwyczaj z dwoma problemami. Pierwszy z nich polega na typie zmiennej, w jakiej przechowywana jest wartość numeru telefonicznego. Zazwyczaj jest to zmienna typu tekstowego, choć zdarzają się także zmienne liczbowe. Wtedy oczywiście nie mamy co mówić o standardzie E.164, który wymaga podawania numeru wraz z kodem kraju. Dlatego najpierw powinniśmy sprawdzić jakiego typu zmienną otrzymujemy. Zmienną typu liczbowego zamieniamy na ciąg znaków.

Drugi problem to sam format zapisanie numeru telefonicznego. Weźmy na przykład krakowski numer +48123456789. Jest to numer telefonu stacjonarnego. W bazach danych możemy spotkać go zapisanego na bardzo wiele sposobów: 48123456789 lub 12 345 6789, albo (0)12-34-56-789. Z punktu widzenia człowieka są to poprawne zapisy. Jednak aplikacje nie będą sobie potrafiły z nim poradzić. One oczekują zazwyczaj zapisu w formacie E.164.

Biblioteka phonenumbers

W repozytorium PyPi znajdziemy kilka bibliotek przeznaczonych do operacji na numerach telefonicznych. Najbardziej przypadła biblioteka phonenumbers. Operacje na numerze telefonu rozpoczynamy od utworzenia obiektu za pomocą metody parse(). Wymaga ona podania dwóch parametrów – ciągu tekstowego zawierającego numer telefonu oraz oznaczenie kraju, w którym dany numer się znajduje. Ostatni parametr może przyjąć też wartość None. W takim wypadku możemy spodziewać się większej liczby błędów związanych z rozpoznawaniem numeru telefonicznego. W samym ciągu znaków zawsze może znajdować się więcej niż jeden numer telefonu, co pozwala na analizowanie całych zdań. Wykryte numery telefonów zapisane są wtedy w postaci listy.

import phonenumbers

my_number = phonenumbers.parse("(12) 345-67-89", "PL")

Zaimportowany ten sposób numer telefonu możemy następnie wykorzystać zapisując go w jednym z czterech formatów.

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.NATIONAL))
12 345 67 89

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+48 12 345 67 89

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.E164))
+48123456789

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.RFC3966))
tel:+48-12-345-67-89

Ten sposób wprowadzenia numeru telefonu nie jest doskonały. W pewnych sytuacjach może on powodować błędy. Jest to związane z wymogiem podania identyfikatora kraju, z którego numer pochodzi. Pamiętajmy, że różne kraje mogą mieć różne długości numerów telefonów. Inaczej też w zapisie rozdziela się część identyfikującą operatora albo region, od samego numeru telefonicznego. W niektórych przypadkach nasz krakowski numer zostanie niepoprawnie rozpoznany jako numer amerykański. Nawet mimo podania przez nas kodu kraju.

my_number = phonenumbers.parse("123456789", "PL")
print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+48 12 345 67 89

my_number = phonenumbers.parse("0123456789", "PL")
print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+48 0123456789

my_number = phonenumbers.parse("00123456789", "PL")
print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+1 23456789

W tej bibliotece jest to zabieg zamierzony, który ma pozwolić nam na operowanie poprawnymi numerami telefonów z innych krajów, mimo że importując je do biblioteki wskazujemy jednoznacznie Polskę.

Czy numery telefonów są poprawne?

Jeżeli dysponujemy już obiektem reprezentującym numer telefonu to możemy sprawdzić, czy jest on poprawnie skonstruowany.

my_number = phonenumbers.parse("123456789", "PL")

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+48 12 345 67 89

print(phonenumbers.is_valid_number(my_number))
True

my_number = phonenumbers.parse("00123456789", "PL")

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+1 23456789

print(phonenumbers.is_valid_number(my_number))
False

Bardzo ciekawa jest bliźniacza metoda is_possible_number(), która zwraca wartość True, gdy numer potencjalnie jest prawidłowy, lecz brakuje w nim jakiś elementów. Jeszcze parę lat temu w Polsce na numery stacjonarne w danym obszarze numeracyjnym mogliśmy dzwonić bez podawania numeru kierunkowego. Wybieraliśmy wtedy tak zwany numer skrócony. Teraz jest to już niemożliwe. Wspomniana metoda pozwoli nam jednak rozpoznać czy potencjalnie mamy do czynienia z zapisem numeru skróconego.

my_number = phonenumbers.parse("3456789", "PL")

print(phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL))
+48 3456789

print(phonenumbers.is_valid_number(my_number))
False

print(phonenumbers.is_possible_number(my_number))
True

Podsumowanie

Biblioteka phonenumbers nie jest nowa. Nie jest ona już intensywnie rozwijana od paru lat. Oferuje jednak wystarczająco wiele funkcjonalności, które wykorzystamy przy automatyzowaniu skryptów związanych z telefonią. Pełny zakres dostępnych metod i ich możliwości znajdziemy w dokumentacji.

E-BOOK

Zaczynasz swój pierwszy projekt związany z automatyzacją?

Ten e-book jest dla Ciebie! Zawiera sprawdzone podejście, które realizowałem w wielu projektach. Sprawdź co możesz zrobić, by odnieść sukces!


Subscribe
Powiadom o
guest

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.

4 komentarzy
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
spex
13/01/2021 08:39

Nie jestem pewien, czy forma +480123456789 jest prawidłowa. Chyba u nas dostaniesz informacje, iż należy dzwonić bez zera.

spex
Reply to  Piotr Wojciechowski
13/01/2021 09:57

Tu mi nawet nie chodzi, co jest w przykładzie. Ale co faktycznie zwróci bibloteka?

ZdradziĆ Ci sekretY udanego projektu automatyzacji?

(link otwiera się w nowym oknie)