2008-10-09 11 views
23

¿Cuál es la mejor forma de convertir números de teléfono a formato internacional (E.164) usando Java?¿Cuál es la mejor manera de convertir números de teléfono a formato internacional (E.164) usando Java?

Dado un 'número de teléfono' y una identificación de país (digamos un código de país ISO), me gustaría convertirlo en un número de teléfono de formato internacional estándar E.164.

Estoy seguro de que puedo hacerlo a mano con bastante facilidad, pero no estoy seguro de que funcione correctamente en todas las situaciones.

¿Qué framework/biblioteca/utilidad Java recomendaría para lograr esto?

P.S. El 'número de teléfono' podría ser cualquier cosa identificable por el público en general - como

* (510) 786-0404 
* 1-800-GOT-MILK 
* +44-(0)800-7310658 

esto último es mi favorito - es cómo algunas personas escriben su número en el Reino Unido y significa que usted debe utilizar el + 44 o se debe utilizar el 0.

el número formato E.164 debe ser todo numérica, y utilizando un código internacional de país completo (por ejemplo, + 44)

+0

echa un vistazo a este sitio: http://droidprism.blogspot.com/2013/06/decision-with-international-numbers-in.html –

Respuesta

45

Google proporciona una biblioteca para trabajar con números de teléfono. El mismo que utilizan para Android

http://code.google.com/p/libphonenumber/

String swissNumberStr = "044 668 18 00" 
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 
try { 
    PhoneNumber swissNumberProto = phoneUtil.parse(swissNumberStr, "CH"); 
} catch (NumberParseException e) { 
    System.err.println("NumberParseException was thrown: " + e.toString()); 
} 

// Produces "+41 44 668 18 00" 
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.INTERNATIONAL)); 
// Produces "044 668 18 00" 
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.NATIONAL)); 
// Produces "+41446681800" 
System.out.println(phoneUtil.format(swissNumberProto, PhoneNumberFormat.E164)); 
+0

Gracias. Esto parece muy prometedor. Voy a probarlo – Vihung

+0

La biblioteca se ve bien. Lo único que me impide usarlo en la aplicación web es el tamaño del archivo JavaScript :-( –

0

Ésta es una tarea muy difícil como números de teléfono están escritos diferente casi en cada país.

Solíamos mantener una lista de REGEXP (admitíamos 19 formatos) para analizar 3 partes de un número y luego convertimos esas 3 partes a "+ {1} {2} {3}".

Primero ordena los rexexps por más específico y luego toma el primero que tiene éxito en el análisis.

11

Hablando de la experiencia al escribir este tipo de cosas, es realmente difícil de hacer con el 100% de fiabilidad. He escrito un código Java para hacer esto que es razonablemente bueno en el procesamiento de los datos que tenemos, pero no será aplicable en todos los países. Las preguntas que debe formular son:

¿El carácter de las asignaciones de números es coherente entre países? Los Estados Unidos usan mucho de esto (por ejemplo, 1800-GOT-MILK) pero en Australia, como un ejemplo, es bastante raro. Lo que tendría que hacer es asegurarse de que estaba haciendo la asignación correcta para el país en cuestión si varía (puede que no). No sé qué hacen los países que usan diferentes alfabetos (por ejemplo, Cyrilic en Rusia y los antiguos países del bloque oriental);

Tienes que aceptar que tu solución no será 100% y no deberías esperar que así sea. Debe adoptar un enfoque de "mejor suposición". Por ejemplo, no hay manera real de saber que 132345 es un número de teléfono válido en Australia, como lo es 1300 123 456, pero que estos son los únicos dos patrones que son para números 13xx y no son exigibles desde el extranjero;

También debe preguntar si desea validar regiones (códigos de área). Creo que EE. UU. Usa un sistema en el que el segundo dígito del código de área es un 1 o un 0. Esto puede haber sido una vez, pero no estoy seguro de si todavía se aplica. En cualquier caso, muchos otros países tendrán otras reglas. En Australia, los códigos de área válidos para teléfonos fijos y móviles (celulares) son de dos dígitos (el primero es 0). 08, 03 y 04 son todos válidos. 01 no es. ¿Cómo se puede atender eso? ¿Quieres?

Los países usan diferentes convenciones sin importar cuántos dígitos escriban. Debes decidir si quieres aceptar algo que no sea la "norma".Todos estos son comunes en Australia:

  • (02) 1234 5678
  • 0411 123 123 (pero nunca he visto 04 1112 3456)
  • 02-1234-5678
  • 1300-234-234
  • +44 78 1234 1234
  • +44 (0) 78 1234 1234
  • + 44-78-1234-1234
  • + 44- (0) 78-1234-1234
  • 0011 44 ​​78 1234 1234 (0011 es el código de marcación estándar internacional)
  • (44) 078 1234 1234 (no común)

y eso es jus fuera de mi cabeza Para un país En Francia, por ejemplo, es común escribir el número de teléfono en pares de números (12 34 56 78) y lo pronuncian de la misma manera: en lugar de:

un (uno), deux (dos), trois (tres), ...

su

Douze (doce), trente-quatre (treinta y cuatro), ...

¿quieres atender a ese nivel de diferencia cultural? Asumiría que no, pero vale la pena considerar la pregunta en caso de que las reglas sean demasiado estrictas.

También algunas personas pueden agregar números de extensión en los números de teléfono, posiblemente con "ext" o una abreviatura similar. ¿Quieres atender eso?

Lo sentimos, no hay código aquí. Solo una lista de preguntas para hacerse y temas que debe considerar. Como han dicho otros, una serie de expresiones regulares puede hacer mucho de lo anterior pero, en última instancia, los campos de números de teléfono son (en su mayoría) texto de forma libre al final del día.

+0

Las asignaciones de caracteres a dígitos son consistentes dentro de cada país donde se utilizan ampliamente (o, indicando lo mismo: en los países donde no hay un mapeo uniforme, los números de teléfono no se representarán como letras). Dado que el código de país está disponible, también puede identificar * qué * mapeo es necesario. – MSalters

+0

Excelente publicación. Por cierto, nosotros los mexicanos también agrupamos (y pronunciamos) números de teléfono en pares. Al menos para mí es más fácil memorizar solo 4 números individuales en lugar de 8 (tiendo a sufrir con números de teléfono en inglés). –

+0

Si haces tu tel. no. El formateador se extiende desde java.text.Format, podrá manejar la configuración regional correctamente. –

0

En algunos países puede validar 112 como un número de teléfono válido, pero si coloca un código de país delante de él ya no será válido. En otros países, no puede validar 112, pero puede validar el 911 como un número de teléfono válido.

He visto algunos teléfonos que ponen Q en la tecla 7 y Z en la tecla 9. He visto algunos teléfonos que ponen Q y Z en la tecla 0, y algunos que ponen Q y Z en la tecla 1.

Un código de área que existía ayer podría no existir hoy, y viceversa.

En la mitad de América del Norte (código de país 1), la regla del segundo dígito solía ser 0 o 1 para los códigos de área, pero esa regla desapareció hace 10 años.

1

Gracias por las respuestas. Como se indicó en la pregunta original, estoy mucho más interesado en el formato del número en el formato estándar que en determinar si es un número de teléfono válido (como en genuino).

Tengo actualmente un código hecho a mano que tiene un número de teléfono String (como lo ingresó el usuario) y un contexto de país de origen y contexto de país de destino (el país desde donde se está marcando el número y el país donde número se está marcando - esto es conocido por el sistema) y luego hace la siguiente conversión en pasos

  1. Strip todos los espacios en blanco a partir del número

  2. Traducir todo alfa en dígitos - con ayuda de una tabla de consulta de la carta a dígito (por ejemplo, A -> 2, B -> 2, C -> 2, D -> 3) etc. para el teclado (no sabía que algunos teclados los distribuyen de forma diferente)

  3. Elimine toda la puntuación, manteniendo un "+" anterior, si existe (en caso de que el número ya esté en algún tipo de formato internacional).

  4. Determine si el número tiene un prefijo de marcado internacional para el contexto del país, p. Ej. si el contexto de origen es el Reino Unido, vería si comienza con un '00' - y lo reemplaza con un '+'. Actualmente, no compruebo si los dígitos que siguen al '00' van seguidos del código de marcación internacional para el país de destino. Busco el prefijo de marcación internacional para el país de origen en una tabla de búsqueda (por ejemplo, GB -> '00', US -> '011', etc.)

  5. Determine si el número tiene un prefijo de marcación local para el contexto del país, por ejemplo si el contexto de origen es el Reino Unido, buscaría si comienza con un '0' y lo reemplazaré con un '+' seguido del código de marcación internacional para el país de destino. Busco el prefijo de marcación local para el país de origen en una tabla de búsqueda (por ejemplo, GB -> '0', US -> '1', etc.) y el código de marcación internacional para el país de destino en otra tabla de búsqueda (eg'GB '=' 44' , US = '1')

parece que funciona para todo lo que he echado en ella hasta ahora - a excepción de la 44 (0) 1234-567-890 situación - Agregaré un cheque de caso especial para ese.

Escribir no fue difícil, y puedo agregar casos especiales para cada excepción extraña que encuentre. Pero realmente me gustaría saber si hay una solución estándar.

Las compañías telefónicas parecen lidiar con esto todos los días. Nunca obtengo resultados inconsistentes al marcar números usando la PSTN. Por ejemplo, en los EE. UU. (Donde los teléfonos celulares tienen los mismos códigos de área que las líneas fijas, podría marcar + 1-123-456-7890, o 011-1-123-456-7890 (donde 011 es el prefijo de marcado internacional en el EE. UU. Y 1 es el código de marcación internacional para EE. UU.), 1-123-456-7890 (donde 1 es el prefijo de marcación local en EE. UU.) O incluso 456-7890 (asumiendo que estaba en el código de área 123 en ese momento) y obtengo los mismos resultados cada vez. Supongo que internamente estos números marcados se convierten al mismo formato estándar E.164, y que la conversión se hace en software.

+0

Hay una falla potencial en el paso 5. Es posible que en algún lugar del mundo existan números de teléfono donde el código de área pueda comenzar con el mismo dígito que el prefijo de marcación nacional (NB, no sé si los hay, pero no lo hago). t sabe que tampoco lo hay) y, por lo tanto, no sabe si está eliminando el prefijo o eliminando parte del código de área. (esto no es un problema con los números del Reino Unido o EE. UU.) – grahamparks

0

No conozco una biblioteca estándar o marco disponible para formatear los números de teléfono en E.164.

La solución utilizada para nuestro producto, que requiere formatear la identificación de llamada proporcionada por PBX en E.164, es implementar un archivo (tabla de base de datos) que contenga la información de formato E.164 para todos los países aplicables. Esto tiene la ventaja de que la aplicación se puede actualizar (para manejar todos los casos de esquina extraños en varias redes PSTN) sin requerir cambios en la base del código de producción.

La tabla contiene una fila para cada código de país e información con respecto a la longitud del código de área y la longitud del suscriptor.Puede haber entradas múltiples para un país dependiendo de qué variaciones son posibles con el código de área y la longitud del número de suscriptor.

Utilizando Nueva Zelanda PSTN (parcial) plan de marcado como un ejemplo de la tabla ..

CC AREA_CODE AREA_CODE_LENGTH SUBSCRIBER SUBSCRIBER_LENGTH 
64       1    7 
64   21     2    7 
64  275     3    6 

hacemos algo similar a lo que usted ha descrito, es decir, pele el número de teléfono proporcionado de cualquier carácter no dígitos y luego formatee según varias reglas con respecto a la longitud total del plan numérico, el código de acceso externo y los códigos de acceso internacional/de larga distancia.

+0

Qué tal esto: CC cc AREA_CODE aa AREA_CODE_LENGTH n SUBSCRIBER qué SUBSCRIBER_LENGTH 6 o 7. (Creo que también vi 7 u 8) –

+0

La columna acortada los nombres son razonables, me formatearon esta tabla como arriba solo por razones ilustrativas. No estoy seguro de lo que significan los comentarios para el suscriptor y la longitud de sub tho. – Henk

+0

hola! ¿esa base de datos es pública? ¡muchas gracias! – Leo

1

Para ser sincero, parece que ya tienes la mayoría de las bases cubiertas.

El formato +44 (0) 800 a veces (incorrectamente) utilizado en el Reino Unido es molesto y no es estrictamente válido de acuerdo con E.123, que es la recomendación del UIT-T sobre cómo deben mostrarse los números. Si no tiene una copia de E.123, merece la pena verla.

Por lo que vale, la red telefónica no siempre usa E.164. A menudo habrá un indicador en la señalización RDSI generada por la PBX (o en la red si está conectado a un teléfono a vapor) que le dice a la red si el número que se marca es local, nacional o internacional.

3

Esta fue mi solución:

public static String FixPhoneNumber(Context ctx, String rawNumber) 
{ 
    String  fixedNumber = ""; 

    // get current location iso code 
    TelephonyManager telMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE); 
    String    curLocale = telMgr.getNetworkCountryIso().toUpperCase(); 

    PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); 
    Phonenumber.PhoneNumber  phoneNumberProto; 

    // gets the international dialling code for our current location 
    String    curDCode = String.format("%d", phoneUtil.getCountryCodeForRegion(curLocale)); 
    String    ourDCode = ""; 

    if(rawNumber.indexOf("+") == 0) 
    { 
     int  bIndex = rawNumber.indexOf("("); 
     int  hIndex = rawNumber.indexOf("-"); 
     int  eIndex = rawNumber.indexOf(" "); 

     if(bIndex != -1) 
     { 
      ourDCode = rawNumber.substring(1, bIndex); 
     } 
     else if(hIndex != -1) 
     {    
      ourDCode = rawNumber.substring(1, hIndex); 
     } 
     else if(eIndex != -1) 
     { 
      ourDCode = rawNumber.substring(1, eIndex); 
     } 
     else 
     { 
      ourDCode = curDCode; 
     }   
    } 
    else 
    { 
     ourDCode = curDCode; 
    } 

    try 
    { 
     phoneNumberProto = phoneUtil.parse(rawNumber, curLocale); 
    } 

    catch (NumberParseException e) 
    { 
     return rawNumber; 
    } 

    if(curDCode.compareTo(ourDCode) == 0) 
     fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.NATIONAL); 
    else 
     fixedNumber = phoneUtil.format(phoneNumberProto, PhoneNumberFormat.INTERNATIONAL); 

    return fixedNumber.replace(" ", ""); 
} 

espero que esto ayude a alguien con el mismo problema.

Disfrútalo y úsalo libremente.

Cuestiones relacionadas