Qual é a melhor maneira para converter números de telefone em formato internacional (E.164) usando Java?

StackOverflow https://stackoverflow.com/questions/187216

Pergunta

O que é a melhor maneira para converter números de telefone em formato internacional (E.164) usando Java?

Dado um 'número de telefone e um ID de país (digamos que um código de país ISO), eu gostaria de convertê-lo em um E.164 número de telefone formato padrão internacional.

Tenho certeza de que pode fazê-lo à mão com bastante facilidade - mas eu não ter certeza de que iria funcionar corretamente em todas as situações

.

quadro que Java / biblioteca / utilidade que você recomendaria para fazer isso?

P.S. O 'número de telefone' poderia ser qualquer coisa identificável pelo público em geral - como

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

esse último é o meu favorito -. É como algumas pessoas escrevem o seu número no Reino Unido e significa que você deve usar o 44 ou você deve usar a 0

O número formato E.164 deve ser tudo numérico, e use o código internacional do país inteiro (por exemplo, + 44)

Foi útil?

Solução

O Google fornece uma biblioteca para trabalhar com números de telefone. O mesmo que eles usam 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));

Outras dicas

Falando da experiência em escrever este tipo de coisa, é realmente difícil de fazer com 100% de confiabilidade. Eu escrevi algum código Java para fazer isso que é razoavelmente bom em processar os dados que temos, mas não será aplicável em todos os países. Perguntas que você precisa perguntar são:

Tem o caráter de mapeamentos número consistente entre os países? Os EUA usa um monte de presente (por exemplo, 1800-GOT-leite), mas na Austrália, como um exemplo, o seu muito raro. O que você precisa fazer é garantir que você estava fazendo o mapeamento correto para o país em questão, se ele varia (talvez não). Eu não sei o que os países que usam alfabetos diferentes (por exemplo Cyrilic na Rússia e países do antigo bloco de Leste) fazer;

Você tem que aceitar que sua solução não será 100% e você não deve esperar que ele seja. Você precisa ter uma abordagem "melhor palpite". Por exemplo, não há nenhuma maneira real de saber que 132345 é um número de telefone válido na Austrália, como é de 1300 123 456, mas que estes são os únicos dois padrões que são para 13xx números e eles não são resgatáveis ??do exterior;

Você também tem que perguntar se você quiser regiões Validate (códigos de área). Eu acredito que os EUA utilizam um sistema onde o segundo dígito do código de área é um 1 ou um 0. Isto pode ter sido o caso, mas eu não tenho certeza se ele ainda se aplica. Seja qual for o caso, muitos outros países terão outras regras. Na Austrália, os códigos de área válidos para telefones fixos e telefones móveis (celulares) são dois dígitos (o primeiro é 0). 08, 03 e 04 são todos válidos. 01 não é. Como você atender a isso? Você quer?

Os países usam diferentes convenções não importa quantos dígitos que estão escrevendo. Você tem que decidir se você quer aceitar algo que não seja a "norma". Estes são comuns na Austrália:

  • (02) 1234 5678
  • 02 1234 5678
  • 0411 123 123 (mas eu nunca vi 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 é o código de discagem internacional padrão)
  • (44) 078 1234 1234 (não comum)

E isso é apenas fora do topo da minha cabeça. Para um país. Na França, por exemplo, a sua posição comum a escrita o número de telefone em pares de números (12 34 56 78) e pronunciá-lo dessa maneira também: em vez de:

un (um), deux (dois), trois (três), ...

sua

douze (doze), trente-quatre (trinta e quatro), ...

Do que você quer para atender a esse nível de diferença cultural? Eu diria que não, mas a questão é vale a pena considerar apenas no caso de você fazer as suas regras muito rigoroso.

Além disso, algumas pessoas podem acrescentar números de ramal em números de telefone, possivelmente com "ext" ou abreviatura similar. Você quer atender a isso?

Desculpe, nenhum código aqui. Apenas uma lista de perguntas a fazer a si mesmo e questões a considerar. Como já foi dito, uma série de expressões regulares podem fazer muito do acima, mas em última análise, campos de número de telefone são (principalmente) de texto livre formulário no final do dia.

Esta foi a minha solução:

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 isso ajude alguém com o mesmo problema.

Aproveite e use livremente.

Obrigado pelas respostas. Como afirmado na pergunta original, eu sou muito mais interessados ??na formatação do número para o formato padrão do que eu para determinar se ele é um válido (como em genuína) número de telefone.

Eu tenho alguns artesanal código atualmente que leva uma String número de telefone (como digitado pelo usuário) e um contexto contexto do país de origem e de destino do país (o país de onde o número está a ser marcada, eo país para onde o número está a ser marcada - isso é conhecido para o sistema) e, em seguida, faz o seguinte conversão em etapas

  1. Faixa de todos os espaços a partir do número

  2. Traduzir tudo alfa em dígitos - utilizando uma tabela de pesquisa de carta de dígitos (por exemplo, A -> 2, B -> 2, C -> 2, D -> 3), etc., para o teclado (eu não estava ciente de que alguns teclados distribuí-los de forma diferente)

  3. Faixa de toda a pontuação -. Manter um precedente '+' intacta, se existir (caso o número já está em algum tipo de formato internacional)

  4. Determinar se o número tem um prefixo de discagem internacional para o contexto do país - por exemplo, se contexto de origem é o Reino Unido, gostaria de ver se ele começa com um '00' - e substituí-lo com um '+'. Eu atualmente não verificar se os dígitos após o '00' são seguidos pelo código de discagem internacional para o país de destino. Eu olho para o prefixo de discagem internacional para o país de origem em uma tabela de pesquisa (por exemplo GB -> '00', US -.> '011' etc)

  5. Determinar se o número tem um prefixo de discagem local para o contexto do país - por exemplo, se o contexto de origem é o Reino Unido, gostaria de olhar para ver se ele começa com um '0' - e substituí-lo com um '+' seguido do código de discagem internacional para o país de destino. Eu olho para o prefixo de discagem local para o país de origem em uma tabela de pesquisa (por exemplo, GB -> '0', US -> '1' etc.), eo código de discagem internacional para o país de destino em outra tabela de pesquisa ( eg'GB '=' 44' , R = '1')

Parece que funciona para tudo o que tenho jogado nele até agora - exceto para a situação +44 (0) 1234-567-890 -. Vou acrescentar uma verificação caso especial para que um

Escrevendo não foi difícil - e eu posso adicionar casos especiais para cada exceção estranha me deparo. Mas eu realmente gostaria de saber se existe uma solução padrão.

As empresas de telefonia parecem lidar com essa coisa todos os dias. Eu nunca obter resultados inconsistentes quando discar números usando o PSTN. Por exemplo, nos EUA (onde os telemóveis têm os mesmos códigos de área como telefones fixos, eu poderia marcar + 1-123-456-7890, ou 011-1-123-456-7890 (onde 011 é o prefixo de discagem internacional no dos EUA e 1 é o código internacional de marcação para os EUA), 1-123-456-7890 (onde 1 é o prefixo de marcação local, na US) ou mesmo 456-7890 (assumindo que estava na área de código 123 no momento) e obter os mesmos resultados de cada vez. Presumo que internamente esses números discados são convertidos para o mesmo formato padrão E.164, e que a conversão é feito no software.

Para ser honesto, parece que você tem a maioria das bases já cobertas.

O formato +44 (0) 800 vezes (incorretamente) utilizado no Reino Unido é irritante e não é estritamente válido de acordo com E.123, que é a recomendação ITU-T para a forma como os números devem ser exibidos. Se você não tem uma cópia do E.123 vale a pena dar uma olhada.

Por que vale a pena, a rede telefónica em si não usar sempre E.164. Muitas vezes, haverá uma bandeira na ISDN sinalização gerada pelo PBX (ou na rede se você estiver em um telefone de vapor) que conta a rede se o número discado é local, nacional ou internacional.

Esta é uma tarefa muito difícil como números de telefone são escritos de forma diferente quase em cada país.

Nós usado para manter uma lista de expressões regulares (que apoiou 19 formatos) para analisar 3 partes de um número e, em seguida, convertido essas 3 partes para "+ {1} {2} {3}".

Classificar regexps por mais específico em primeiro lugar e, em seguida, tomar o primeiro que consegue análise.

Em alguns países, você pode validar o 112 como um número de telefone válido, mas se você ficar um código de país na frente dele não será válida. Em outros países, você não pode validar 112, mas você pode validar 911 como um número de telefone válido.

Eu vi alguns telefones que colocam Q na tecla 7 e Z na tecla 9. Eu vi alguns telefones que colocam Q e Z na tecla 0, e alguns que colocar Q e Z na tecla 1.

Um código de área que existia ontem não poderia existir hoje, e vice-versa.

Na metade da América do Norte (código do país 1), a segunda regra dígitos costumava ser 0 ou 1 para códigos de área, mas essa regra foi embora há 10 anos.

Eu não estou ciente de uma biblioteca padrão ou estrutura disponível para a formatação de números de telefone em E.164.

A solução utilizada para o nosso produto, que exige formatação PBX fornecido chamador-id em E.164, é implantar um arquivo (tabela de banco de dados) que contém as informações de formato E.164 para todos os países aplicáveis. Isto tem a vantagem que o aplicativo pode ser atualizado (para lidar com todos os casos de canto estranhos em várias redes PSTN) w / out exigindo mudanças na base de código de produção.

A tabela contém uma linha para cada código do país e informações sobre comprimento código de área e comprimento assinante. Pode haver várias entradas para um país dependendo do que são possíveis com código de área e número de assinante comprimentos variações.

Usando Nova Zelândia PSTN (parcial) plano discar como um exemplo da tabela ..

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

Fazemos algo semelhante ao que você descreveu, ou seja, tira o número de telefone fornecido de quaisquer caracteres não-dígito e, em seguida, formato baseado em várias regras sobre o comprimento total plano de número, código de acesso exterior, e de longa distância / códigos de acesso internacionais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top