java - que - normas itu telecomunicaciones
¿Cuál es la mejor forma de convertir números de teléfono a formato internacional(E.164) usando Java? (8)
¿Cuál es la mejor forma 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?
PD: 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
el último es mi favorito, así es como algunas personas escriben su número en el Reino Unido y significa que debes usar el +44 o debes usar el 0.
El número de formato E.164 debe ser totalmente numérico y usar el código de país internacional completo (p. Ej., +44)
Hablando de la experiencia al escribir este tipo de cosas, es realmente difícil hacerlo con un 100% de confiabilidad. 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 hacer son:
¿El carácter de las asignaciones de números es coherente entre los 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 una 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 se pueden llamar 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 convenciones diferentes 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
- 02 1234 5678
- 0411 123 123 (pero nunca he visto 04 1112 3456)
- 131 123
- 13 1123
- 131 123
- 1 300 123 123
- 1300 123 123
- 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 internacional estándar)
- (44) 078 1234 1234 (no es común)
Y eso está 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), ...
sus
douze (doce), trente-quatre (treinta y cuatro), ...
¿Quieres atender 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.
Además, 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 siento, 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.
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 en frente, 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 existió 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.
Esta es una tarea muy difícil ya que los números de teléfono se escriben de manera diferente en casi todos los países.
Solíamos mantener una lista de REGEXP (apoyamos 19 formatos) para analizar 3 partes de un número y luego convertimos esas 3 partes a "+ {1} {2} {3}".
Clasifique las expresiones regulares por más específico primero y luego tome la primera que tenga éxito en el análisis.
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).
Actualmente tengo un código hecho a mano que toma 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 marca el número y el país donde se marca el número) - esto es conocido por el sistema) y luego realiza la siguiente conversión en pasos
Elimina todos los espacios en blanco del número
Traduzca todos los alfa en dígitos - usando una tabla de búsqueda de letra a dígito (ej. A -> 2, B -> 2, C -> 2, D -> 3) etc. para el teclado (no estaba al tanto que algunos teclados distribuyen estos de manera diferente)
Elimine toda la puntuación, manteniendo intacto el "+" anterior, si existe (en caso de que el número ya esté en algún tipo de formato internacional).
Determine si el número tiene un prefijo de marcación internacional para el contexto del país, por ejemplo, si el contexto de origen es el Reino Unido, vería si comienza con un ''00'', y reemplácelo 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.)
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, quisiera ver si comienza con un ''0'', y reemplácelo con un ''+'' seguido del marcado internacional. código 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 lanzado hasta el momento, excepto por la situación del +44 (0) 1234-567-890. Agregaré una verificación de caso especial para esa.
Escribirlo 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 obtener 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 realiza en software.
No conozco una biblioteca o marco estándar disponible para formatear números de teléfono en E.164.
La solución utilizada para nuestro producto, que requiere el formato de identificación de llamada proporcionada por PBX en E.164, es desplegar un archivo (tabla de base de datos) que contiene la información de formato E.164 para todos los países aplicables. Esto tiene la ventaja de que la aplicación puede actualizarse (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.
Uso del plan de marcado PSTN (parcial) de Nueva Zelanda como 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 ha descrito, es decir, eliminamos el número de teléfono provisto de caracteres que no sean dígitos y luego formateamos 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.
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.
Google proporciona una biblioteca para trabajar con números de teléfono. El mismo que usan 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));
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.
Disfruta y usa libremente.