Рубрики
Без рубрики

Проверка и форматирование телефонных номеров в Python с помощью телефонных номеров

В этом уроке мы узнаем, как анализировать, проверять и извлекать телефонные номера в Python с помощью библиотеки телефонных номеров.

Автор оригинала: Ruslan Hasanov.

Вступление

Проверка телефонных номеров может быть очень сложной задачей. Формат телефонного номера может варьироваться в зависимости от страны. Черт возьми, она также может варьироваться в пределах одной и той же страны! Некоторые страны используют один и тот же код страны, в то время как некоторые другие страны используют более одного кода страны. Согласно примеру из репозитория Google libphonenumber GitHub , США, Канада и Карибские острова имеют один и тот же код страны ( +1 ). С другой стороны, можно звонить на телефонные номера из Косово по сербским, словенским и марокканским кодам стран.

Это лишь некоторые из проблем, связанных с идентификацией или проверкой телефонных номеров. На первый взгляд, можно, по крайней мере, проверить код страны телефонного номера с помощью регулярного выражения . Однако это означает, что вам придется написать собственное правило регулярных выражений для каждой страны мира, просто чтобы проверить код страны. Кроме того, некоторые операторы мобильной связи имеют свои собственные правила (например, определенные цифры могут использовать только определенный диапазон номеров). Вы можете видеть, что все может быстро выйти из-под контроля и сделать почти невозможным для нас проверить ввод номера телефона самостоятельно.

К счастью, существует библиотека Python, которая может помочь нам легко и эффективно пройти процесс проверки. Библиотека Python Phonenumbers является производной от библиотеки Google libphonenumber , которая также доступна для других языков программирования, таких как C++, Java и JavaScript.

В этом уроке мы узнаем, как анализировать, проверять и извлекать телефонные номера, а также как извлекать дополнительную информацию из телефонных номеров, например, информацию о носителе, часовом поясе или геокодере.

Использование библиотеки очень прямолинейно, и обычно она используется следующим образом:

import phonenumbers
from phonenumbers import carrier, timezone, geocoder

my_number = phonenumbers.parse("+447986123456", "GB")

print(phonenumbers.is_valid_number(my_number))
print(carrier.name_for_number(my_number, "en"))
print(timezone.time_zones_for_number(my_number))
print(geocoder.description_for_number(my_number, 'en'))

И вот результат:

True
EE
('Europe/Guernsey', 'Europe/Isle_of_Man', 'Europe/Jersey', 'Europe/London')
United Kingdom

Давайте начнем с настройки нашей среды и установки библиотеки.

Установка телефонных номеров

Во-первых, давайте создадим и активируем нашу виртуальную среду:

$ mkdir phonenumbers && cd phonenumbers
$ python3 -m venv venv
$ . venv/bin/active # venv\Scripts\activate.bat on Windows

Затем мы устанавливаем библиотеку Python Phonenumbers:

$ pip3 install Phonenumbers

Этот учебник будет использовать версию библиотеки телефонных номеров 8.12.19 .

Теперь мы готовы начать знакомство с библиотекой телефонных номеров.

Разбор телефонных номеров с помощью Python phonenumbers

Независимо от того, получаете ли вы пользовательский ввод из веб-формы или других источников, например извлечение из какого-либо текста (подробнее об этом позже в этом учебнике), входной номер телефона, скорее всего, будет строкой. В качестве первого шага нам нужно будет разобрать его с помощью телефонных номеров и превратить в экземпляр Телефонного номера , чтобы мы могли использовать его для проверки и других функций.

Мы можем разобрать номер телефона с помощью метода parse() :

import phonenumbers

my_string_number = "+40721234567"
my_number = phonenumbers.parse(my_string_number)

Метод phonenumbers.parse() принимает строку телефонного номера в качестве обязательного аргумента. Вы также можете передать информацию о стране в формате ISO Alpha-2 в качестве необязательного аргумента. Возьмем, к примеру, следующий код:

my_number = phonenumbers.parse(my_string_number, "RO")

“RO” означает Румынию в формате ISO Alpha-2. Вы можете проверить другие альфа-2 и числовые коды стран с этого веб-сайта . В этом уроке для простоты я опущу код страны ISO Alpha-2 для большинства случаев и включу его только тогда, когда это строго необходимо.

Метод phonenumbers.parse() уже имеет некоторые встроенные базовые правила проверки, такие как длина числовой строки, проверка начального нуля или знака + . Обратите внимание, что этот метод вызовет исключение, когда какое-либо из необходимых правил не будет выполнено. Поэтому не забудьте использовать его в блоке try/catch в вашем приложении .

Теперь, когда мы правильно проанализировали наш номер телефона, давайте перейдем к проверке.

Проверка телефонных номеров с помощью Python Phonenumbers

Телефонные номера имеют два метода проверки действительности телефонного номера. Главное отличие этих методов-скорость и точность.

Чтобы уточнить, давайте начнем с is_possible_number() :

import phonenumbers

my_string_number = "+40021234567"
my_number = phonenumbers.parse(my_string_number)
print(phonenumbers.is_possible_number(my_number))

И выход будет таким:

True

Теперь давайте используем тот же номер, но на этот раз с помощью метода is_valid_number() :

import phonenumbers

my_string_number = "+40021234567"
my_number = phonenumbers.parse(my_string_number)
print(phonenumbers.is_valid_number(my_number))

Даже если входные данные были одинаковыми, результат будет другим:

False

Причина в том, что метод is_possible_number() быстро угадывает действительность телефонного номера, проверяя длину анализируемого номера, в то время как метод is_valid_number() выполняет полную проверку, проверяя длину, префикс телефонного номера и регион.

При итерации по большому списку телефонных номеров использование phone numbers.is_possible_number() даст более быстрые результаты по сравнению с phonenumbers.is_valid_number() . Но, как мы видим здесь, эти результаты не всегда могут быть точными. Это может быть полезно для быстрого устранения телефонных номеров, которые не соответствуют длине. Так что используйте его на свой страх и риск.

Извлечение и форматирование телефонных номеров с помощью Python Phonenumbers

Пользовательский ввод-это не единственный способ получить или собрать телефонные номера. Например, у вас может быть паук/искатель, который будет читать определенные страницы с веб-сайта или документа и извлекать телефонные номера из текстовых блоков. Это звучит как сложная проблема, но, к счастью, библиотека телефонных номеров предоставляет нам именно ту функциональность, которая нам нужна, с помощью метода PhoneNumberMatcher(text, region) .

PhoneNumberMatcher принимает текстовый блок и область в качестве аргумента, а затем повторяет итерацию, чтобы вернуть соответствующие результаты в виде объектов PhoneNumberMatch .

Давайте используем PhoneNumberMatcher со случайным текстом:

import phonenumbers

text_block = "Our services will cost about 2,200 USD and we will deliver the product by the 10.10.2021. For more information, you can call us at +44 7986 123456 or send an e-mail to [email protected]"

for match in phonenumbers.PhoneNumberMatcher(text_block, "GB"):
    print(match)

Это приведет к печати соответствующих телефонных номеров вместе с их индексом в строке:

PhoneNumberMatch [131,146) +44 7986 123456

Возможно, вы заметили, что наш номер отформатирован в стандартизированном международном формате и разделен пробелами. Это не всегда может быть так в реальных сценариях. Вы можете получить свой номер в других форматах, например, разделенный на тире или отформатированный в национальном (а не международном) формате.

Давайте проверим метод PhoneNumberMatcher() с другими форматами телефонных номеров:

import phonenumbers

text_block = "Our services will cost about 2,200 USD and we will deliver the product by the 10.10.2021. For more information you can call us at +44-7986-123456 or 020 8366 1177 send an e-mail to [email protected]"

for match in phonenumbers.PhoneNumberMatcher(text_block, "GB"):
    print(match)

Это привело бы к выходу:

PhoneNumberMatch [130,145) +44-7986-123456
PhoneNumberMatch [149,162) 020 8366 1177

Несмотря на то, что телефонные номера встроены глубоко в текст с различными форматами с другими номерами, PhoneNumberMatcher успешно возвращает телефонные номера с большой точностью.

Помимо извлечения данных из текста, мы также можем захотеть получить цифры одну за другой от пользователя. Представьте, что пользовательский интерфейс вашего приложения работает аналогично современным мобильным телефонам и форматирует телефонные номера по мере ввода. Например, на вашей веб-странице вы можете передать данные в свой API с каждым событием onkeyup и использовать AsYouTypeFormatter() для форматирования номера телефона с каждой входящей цифрой.

Поскольку часть пользовательского интерфейса выходит за рамки этой статьи, мы будем использовать базовый пример для AsYouTypeFormatter . Чтобы смоделировать форматирование на лету, давайте перейдем к интерпретатору Python:

>>> import phonenumbers
>>> formatter = phonenumbers.AsYouTypeFormatter("TR")
>>> formatter.input_digit("3")
'3'
>>> formatter.input_digit("9")
'39'
>>> formatter.input_digit("2")
'392'
>>> formatter.input_digit("2")
'392 2'
>>> formatter.input_digit("2")
'392 22'
>>> formatter.input_digit("1")
'392 221'
>>> formatter.input_digit("2")
'392 221 2'
>>> formatter.input_digit("3")
'392 221 23'
>>> formatter.input_digit("4")
'392 221 23 4'
>>> formatter.input_digit("5")
'392 221 23 45'

Не все вводимые пользователем данные происходят так, как они вводятся. Некоторые формы имеют простые поля ввода текста для телефонных номеров. Однако это не обязательно означает, что мы будем вводить данные в стандартном формате.

Библиотека телефонных номеров также покрыла нас здесь с помощью метода format_number () . Этот метод позволяет нам форматировать телефонные номера в три хорошо известных, стандартизированных формата. Национальный, Международный и E164. Национальные и международные форматы довольно понятны, в то время как формат E164-это международный формат телефонных номеров, который гарантирует, что телефонные номера ограничены 15 цифрами и форматируются {+}{код страны}{номер с кодом города} . Для получения дополнительной информации о E164 вы можете проверить эту страницу Википедии .

Начнем с национального форматирования:

import phonenumbers

my_number = phonenumbers.parse("+40721234567")
national_f = phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.NATIONAL)
print(national_f)

Это вернет хорошо разнесенную строку телефонного номера с национальным форматом:

0721 234 567

Теперь давайте попробуем отформатировать национальный номер как в международном формате:

import phonenumbers

my_number = phonenumbers.parse("0721234567", "RO")  # "RO" is ISO Alpha-2 code for Romania
international_f = phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
print(international_f)

Приведенный выше код вернет хорошо разнесенную строку телефонного номера:

+40 721 234 567

Обратите внимание, что мы передали "RO" в качестве второго параметра в метод parse () . Поскольку входной номер является национальным номером, он не имеет префикса кода страны, чтобы намекнуть на страну. В этих случаях нам нужно указать страну с ее кодом ISO Alpha-2, чтобы получить точный результат. Исключение кодов стран numeric и ISO Alpha-2 приведет к исключению NumberParseException: (0) Отсутствует или недопустим регион по умолчанию. .

Теперь давайте попробуем вариант форматирования E164 . Мы передадим национальную строку в качестве входных данных:

import phonenumbers

my_number = phonenumbers.parse("0721234567", "RO")
e164_f=phonenumbers.format_number(my_number, phonenumbers.PhoneNumberFormat.E164)
print(e164_f)

Вывод будет очень похож на PhoneNumberFormat.МЕЖДУНАРОДНЫЙ , за исключением пробелов:

+40721234567

Это очень полезно, когда вы хотите передать номер в фоновый API. API нередко ожидают, что телефонные номера будут строками без интервалов.

Получить дополнительную информацию по номеру телефона

Номер телефона загружается с данными о пользователе, которые могут вас заинтересовать. Вы можете использовать различные API или конечные точки API в зависимости от оператора конкретного телефонного номера, поскольку это играет определенную роль в стоимости продукта. Возможно, вы захотите отправлять уведомления о рекламных акциях в зависимости от часового пояса вашего клиента (номера телефона), чтобы не отправлять ему сообщение посреди ночи. Или вы можете получить информацию о местоположении телефонного номера, чтобы предоставить соответствующую информацию. Библиотека телефонных номеров предоставляет необходимые инструменты для удовлетворения этих потребностей.

Чтобы начать с местоположения, мы будем использовать метод description_for_number() из класса geocoder . Этот метод принимает в качестве параметров анализируемый номер телефона и краткое название языка.

Давайте попробуем это с нашим предыдущим поддельным номером:

import phonenumbers
from phonenumbers import geocoder

my_number = phonenumbers.parse("+447986123456")
print(geocoder.description_for_number(my_number, "en"))

При этом будет распечатана страна происхождения телефонного номера:

United Kingdom

Короткие языковые названия довольно интуитивно понятны. Давайте попробуем получить вывод на русском языке:

import phonenumbers
from phonenumbers import geocoder

my_number = phonenumbers.parse("+447986123456")
print(geocoder.description_for_number(my_number, "ru"))

А вот вывод на котором написано Великобритания по русски:

Соединенное Королевство

Вы можете попробовать его с другими языками ваших предпочтений, такими как “de”, “fr”, “zh” и т. Д.

Как уже упоминалось ранее, вы можете сгруппировать свои телефонные номера по их операторам, так как в большинстве случаев это повлияет на стоимость. Чтобы уточнить, библиотека телефонных номеров, вероятно, предоставит большинство имен операторов точно, но не на 100%.

Сегодня в большинстве стран можно получить свой номер от одного оператора, а затем перенести тот же номер на другой оператор, оставив номер телефона точно таким же. Поскольку Телефонные номера-это всего лишь автономная библиотека Python, обнаружить эти изменения невозможно. Поэтому лучше всего подходить к названиям носителей как к эталону, а не как к факту.

Мы будем использовать метод name_for_number() из класса carrier :

import phonenumbers
from phonenumbers import carrier

my_number = phonenumbers.parse("+40721234567")
print(carrier.name_for_number(my_number, "en"))

При этом будет отображаться исходный носитель телефонного номера, если это возможно:

Vodafone

Примечание : Как указано в оригинальных документах Python Phonenumbers, информация о носителе доступна для мобильных номеров в некоторых странах, но не во всех.

Другой важной частью информации о телефонном номере является его часовой пояс. Метод time_zones_for_number() вернет список часовых поясов, к которым принадлежит это число. Мы импортируем его из номера телефонов.часовой пояс :

import phonenumbers
from phonenumbers import timezone

my_number = phonenumbers.parse("+447986123456")
print(timezone.time_zones_for_number(my_number))

Это приведет к печати следующих часовых поясов:

('Europe/Guernsey', 'Europe/Isle_of_Man', 'Europe/Jersey', 'Europe/London')

На этом наш учебник по Python Phonenumbers заканчивается.

Вывод

Мы научились разбирать телефонные номера с помощью метода parse () , извлекать номера из текстовых блоков с помощью метода PhoneNumberMatcher() , получать телефонные номера цифра за цифрой и форматировать их с помощью метода AsYouTypeFormatter() , используйте различные методы проверки с помощью is_possible_number() и is_possible_number() , форматируйте номера с помощью NATIONAL , INTERNATIONAL и E164 методов форматирования, а также извлекайте дополнительную информацию из телефонных номеров с помощью geocoder , carrier и timezone классов.

Не забудьте проверить оригинальное репо GitHub библиотеки телефонных номеров . Кроме того, если у вас есть какие-либо вопросы, не стесняйтесь комментировать их ниже.