Validación y formato de números de teléfono en Python con números de teléfono

En este tutorial, aprenderemos cómo analizar, validar y extraer números de teléfono en Python con la biblioteca de números de teléfono.

Introducción

Validar números de teléfono puede ser una tarea muy desafiante. El formato de un número de teléfono puede variar de un país a otro. ¡Diablos, también puede variar dentro del mismo país! Algunos países comparten el mismo código de país, mientras que otros países usan más de un código de país. Según un ejemplo del Repositorio libphonenumber GitHub de Google, EE. UU., Canadá y las islas del Caribe comparten el mismo código de país ( +1). Por otro lado, es posible llamar a los números de teléfono de Kosovo con los códigos de país de Serbia, Eslovenia y Marruecos.

Estos son solo algunos de los desafíos en la identificación o validación de números de teléfono. A primera vista, al menos se puede validar el código de país de un número de teléfono con un RegEx. Sin embargo, esto significa que tendría que escribir una regla RegEx personalizada para cada país del mundo, solo para validar un código de país. Además de eso, algunos operadores de telefonía móvil tienen sus propias reglas (por ejemplo, ciertos dígitos solo pueden usar un cierto rango de números). Puede ver que las cosas pueden salirse de control rápidamente y hacer que sea casi imposible para nosotros validar las entradas de números de teléfono por nosotros mismos.

Afortunadamente, hay una biblioteca de Python que puede ayudarnos a pasar el proceso de validación de manera fácil y eficiente. La biblioteca Python Phonenumbers se deriva de la biblioteca libphonenumber de Google, que también está disponible para otros lenguajes de programación como C++, Java y JavaScript.

En este tutorial, aprenderemos a analizar, validar y extraer números de teléfono, así como a extraer información adicional de los números de teléfono, como el operador, la zona horaria o los detalles del geocodificador.

El uso de la biblioteca es muy sencillo y normalmente se usa así:

1
2
3
4
5
6
7
8
9
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'))

Y aquí está la salida:

1
2
3
4
True
EE
('Europe/Guernsey', 'Europe/Isle_of_Man', 'Europe/Jersey', 'Europe/London')
United Kingdom

Comencemos configurando nuestro entorno e instalando la biblioteca.

Instalación de números de teléfono {#instalación de números de teléfono}

Primero, creemos y activemos nuestro entorno virtual:

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

Luego instalamos la biblioteca Python Phonenumbers:

1
$ pip3 install Phonenumbers

Este tutorial utilizará la versión de la biblioteca de números de teléfono de 8.12.19.

Ahora estamos listos para comenzar a descubrir la biblioteca de números de teléfono.

Analizar números de teléfono con Python phonenumbers

Ya sea que obtenga la entrada del usuario de un formulario web u otras fuentes, como la extracción de algún texto (más sobre eso más adelante en este tutorial), lo más probable es que el número de teléfono de entrada sea una cadena. Como primer paso, necesitaremos analizarlo usando phonenumbers y convertirlo en una instancia de PhoneNumber para que podamos usarlo para la validación y otras funcionalidades.

Podemos analizar el número de teléfono usando el método parse():

1
2
3
4
import phonenumbers

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

El método phonenumbers.parse() toma una cadena de número de teléfono como argumento obligatorio. También puede pasar la información del país en formato ISO Alpha-2 como argumento opcional. Considere, por ejemplo, el siguiente código en consideración:

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

"RO" significa Rumania en formato ISO Alpha-2. Puede consultar otros códigos alfa-2 y numéricos de países en este sitio web. En este tutorial, por simplicidad, omitiré el código de país ISO Alpha-2 para la mayoría de los casos y lo incluiré solo cuando sea estrictamente necesario.

El método phonenumbers.parse() ya tiene algunas reglas de validación básicas incorporadas, como la longitud de una cadena de números, o verificar un cero inicial o un signo +. Tenga en cuenta que este método generará una excepción cuando no se cumpla alguna de las reglas necesarias. Así que recuerda usarlo en un bloque try/catch en tu aplicación.

Ahora que tenemos nuestro número de teléfono analizado correctamente, procedamos a la validación.

Validar números de teléfono con Python Phonenumbers

Phonenumbers tiene dos métodos para comprobar la validez de un número de teléfono. La principal diferencia entre estos métodos es la velocidad y la precisión.

Para elaborar, comencemos con is_possible_number():

1
2
3
4
5
import phonenumbers

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

Y la salida sería:

1
True

Ahora usemos el mismo número, pero esta vez con el método is_valid_number():

1
2
3
4
5
import phonenumbers

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

Aunque la entrada fuera la misma, el resultado sería diferente:

1
False

La razón es que el método is_possible_number() hace una suposición rápida sobre la validez del número de teléfono comprobando la longitud del número analizado, mientras que el método is_valid_number() ejecuta una validación completa comprobando la longitud, teléfono prefijo numérico y región.

Al iterar sobre una gran lista de números de teléfono, usar phonenumbers.is_possible_number() proporcionaría resultados más rápidos en comparación con phonenumbers.is_valid_number(). Pero como vemos aquí, es posible que estos resultados no siempre sean precisos. Puede ser útil para eliminar rápidamente los números de teléfono que no cumplen con la longitud. A fin de utilizarlo en su propio riesgo.

Extraiga y formatee números de teléfono con Python Phonenumbers

La entrada del usuario no es la única forma de obtener o recopilar números de teléfono. Por ejemplo, puede tener una araña/rastreador que lea ciertas páginas de un sitio web o un documento y extraiga los números de teléfono de los bloques de texto. Suena como un problema desafiante, pero afortunadamente, la biblioteca de números de teléfono nos brinda la funcionalidad que necesitamos, con el método PhoneNumberMatcher (texto, región).

PhoneNumberMatcher toma un bloque de texto y una región como argumento y luego itera para devolver los resultados coincidentes como objetos PhoneNumberMatch.

Usemos PhoneNumberMatcher con un texto aleatorio:

1
2
3
4
5
6
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 [correo electrónico protegido]"

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

Esto imprimirá los números de teléfono coincidentes junto con su índice en la cadena:

1
PhoneNumberMatch [131,146) +44 7986 123456

Es posible que haya notado que nuestro número está formateado en el formato internacional estandarizado y dividido por espacios. Esto puede no ser siempre el caso en escenarios de la vida real. Puede recibir su número en otros formatos, como dividido por guiones o en formato nacional (en lugar de internacional).

Pongamos a prueba el método PhoneNumberMatcher() con otros formatos de números de teléfono:

1
2
3
4
5
6
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 [correo electrónico protegido]"

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

Esto daría como resultado:

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

Aunque los números de teléfono están incrustados profundamente en el texto con una variedad de formatos con otros números, PhoneNumberMatcher devuelve con éxito los números de teléfono con gran precisión.

Además de extraer datos del texto, también podríamos querer obtener los dígitos uno por uno del usuario. Imagine que la interfaz de usuario de su aplicación funciona de manera similar a los teléfonos móviles modernos y formatea los números de teléfono a medida que los escribe. Por ejemplo, en su página web, es posible que desee pasar los datos a su API con cada evento onkeyup y use AsYouTypeFormatter() para formatear el número de teléfono con cada dígito entrante.

Dado que la parte de la interfaz de usuario está fuera del alcance de este artículo, usaremos un ejemplo básico para AsYouTypeFormatter. Para simular el formateo sobre la marcha, saltemos al intérprete de Python:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> 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'

No todas las entradas de los usuarios suceden mientras escriben. Algunos formularios tienen campos de entrada de texto simples para números de teléfono. Sin embargo, eso no significa necesariamente que tendremos datos ingresados ​​en un formato estándar.

La biblioteca Phonenumbers también nos cubrió aquí con el método format_number(). Este método nos permite dar formato a los números de teléfono en tres formatos estandarizados bien conocidos. Nacional, Internacional y E164. Los formatos nacional e internacional se explican por sí mismos, mientras que el formato E164 es un formato de número de teléfono internacional que garantiza que los números de teléfono estén limitados a 15 dígitos y tengan el formato {+}{código de país}{número con código de área}. Para obtener más información sobre E164, puede consultar [esta página de wikipedia] (https://countrycode.org/).

Comencemos con el formato nacional:

1
2
3
4
5
import phonenumbers

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

Esto devolverá una cadena de números de teléfono bien espaciada con el formato nacional:

1
0721 234 567

Ahora intentemos formatear el número nacional como en formato internacional:

1
2
3
4
5
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)

El código anterior devolverá una cadena de números de teléfono bien espaciada:

1
+40 721 234 567

Note que pasamos "RO" como segundo parámetro al método parse(). Dado que el número de entrada es un número nacional, no tiene prefijo de código de país para insinuar el país. En estos casos, necesitamos especificar el país con su código ISO Alpha-2 para obtener un resultado preciso. Si se excluyen los códigos de país numéricos e ISO Alpha-2, se producirá una excepción de “NumberParseException: (0) Región predeterminada faltante o no válida”.

Ahora probemos la opción de formato E164. Pasaremos una cadena nacional como entrada:

1
2
3
4
5
import phonenumbers

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

La salida será muy similar a PhoneNumberFormat.INTERNATIONAL, excepto con los espacios:

1
+40721234567

Esto es muy útil cuando desea pasar el número a una API en segundo plano. No es raro que las API esperen que los números de teléfono sean cadenas sin espacios.

Obtenga información adicional sobre el número de teléfono

Un número de teléfono se carga con datos sobre un usuario que podrían ser de tu interés. Es posible que desee utilizar diferentes API o puntos finales de API según el operador del número de teléfono en particular, ya que esto juega un papel en el costo del producto. Es posible que desee enviar sus notificaciones de promoción según la zona horaria de su cliente (número de teléfono) para no enviarles un mensaje en medio de la noche. O es posible que desee obtener información sobre la ubicación del número de teléfono para que pueda proporcionar información relevante. La biblioteca de números de teléfono proporciona las herramientas necesarias para satisfacer estas necesidades.

Para comenzar con la ubicación, usaremos el método description_for_number() de la clase geocoder. Este método toma un número de teléfono analizado y un nombre de idioma corto como parámetros.

Intentemos esto con nuestro número falso anterior:

1
2
3
4
5
import phonenumbers
from phonenumbers import geocoder

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

Esto imprimirá el país de origen del número de teléfono:

1
United Kingdom

Los nombres cortos de idiomas son bastante intuitivos. Intentemos obtener resultados en ruso:

1
2
3
4
5
import phonenumbers
from phonenumbers import geocoder

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

Y aquí está el resultado que dice el Reino Unido en ruso:

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

Puede probarlo con otros idiomas de su preferencia como "de", "fr", "zh", etc.

Como se mencionó anteriormente, es posible que desee agrupar sus números de teléfono por sus operadores, ya que en la mayoría de los casos tendrá un impacto en el costo. Para aclarar, la biblioteca de números de teléfono probablemente proporcionará la mayoría de los nombres de los operadores con precisión, pero no el 100%.

Hoy en día, en la mayoría de los países, es posible obtener su número de un operador y luego transferir el mismo número a un operador diferente, dejando el número de teléfono exactamente igual. Dado que Phonenumbers es simplemente una biblioteca de Python sin conexión, no es posible detectar estos cambios. Por lo tanto, es mejor acercarse a los nombres de los transportistas como una referencia, en lugar de un hecho.

Usaremos el método name_for_number() de la clase carrier:

1
2
3
4
5
import phonenumbers
from phonenumbers import carrier

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

Esto mostrará el operador original del número de teléfono si es posible:

1
Vodafone

Nota: Como se menciona en los documentos originales de Python Phonenumbers, la información del operador está disponible para números móviles en algunos países, no en todos.

Otra información importante sobre un número de teléfono es su zona horaria. El método time_zones_for_number() devolverá una lista de zonas horarias a las que pertenece el número. Lo importaremos desde phonenumbers.timezone :

1
2
3
4
5
import phonenumbers
from phonenumbers import timezone

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

Esto imprimirá las siguientes zonas horarias:

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

Esto concluye nuestro tutorial sobre Python Phonenumbers.

Conclusión

Aprendimos cómo analizar números de teléfono con el método parse(), extraer números de bloques de texto con PhoneNumberMatcher(), obtener los números de teléfono dígito por dígito y formatearlos con AsYouTypeFormatter(), usar diferentes métodos de validación con is_possible_number() y is_possible_number(), formatee los números usando los métodos de formato NATIONAL, INTERNATIONAL y E164, y extraiga información adicional de los números de teléfono usando geocoder, carrier y timezone clases

Recuerda consultar el repositorio original de GitHub de la biblioteca Phonenumbers. Además, si tiene alguna pregunta en mente, no dude en comentar a continuación. inuación.