Проверка и форматирование телефонных номеров в Python

Введение Проверка телефонных номеров может быть очень сложной задачей. Формат номера телефона может отличаться от страны к стране. Черт возьми, это может также отличаться в пределах одной страны! Некоторые страны используют один и тот же код страны, в то время как некоторые другие страны используют более одного кода страны. Согласно примеру из репозитория Google libphonenumber на GitHub [https://github.com/google/libphonenumber/blob/master/FALSEHOODS.md], США, Канада и Карибские острова имеют один и тот же код страны.

Вступление

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

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

К счастью, есть библиотека 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 

В этом руководстве будет использоваться библиотека Phonenumbers версии 8.12.19 .

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

Разбор номера телефонов номера телефонов Python

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

Мы можем разобрать номер телефона с помощью метода 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. Вы можете проверить другие коды стран Alpha-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() выполняет полную проверку, проверяя длину, префикс телефонного номера и регион.

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

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

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

PhoneNumberMatcher принимает текстовый блок и область в качестве аргумента, а затем выполняет PhoneNumberMatch чтобы вернуть соответствующие результаты в виде объектов 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' 

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

Библиотека Phonenumbers также предоставила нам 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, чтобы получить точный результат. Исключение числового кода страны и кода страны ISO Alpha-2 вызовет исключение NumberParseException: (0) Missing or invalid default region. .

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

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

Результат будет очень похож на PhoneNumberFormat.INTERNATIONAL , за исключением пробелов:

 +40721234567 

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

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

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

Для начала воспользуемся методом 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» и т. Д.

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

Сегодня в большинстве стран можно получить свой номер у одного оператора связи, а затем перенести тот же номер на другого оператора, оставив при этом номер телефона неизменным. Поскольку Phonenumbers - это просто автономная библиотека 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() вернет список часовых поясов, которым принадлежит номер. Мы импортируем его из phonenumbers.timezone :

 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.

Заключение

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

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

comments powered by Disqus

Содержание