Como validar números de telefone usando regex

920

Estou tentando montar um regex abrangente para validar números de telefone. Idealmente, ele lidaria com formatos internacionais, mas deve lidar com os formatos dos EUA, incluindo o seguinte:

  • 1-234-567-8901
  • 1-234-567-8901 x1234
  • 1-234-567-8901 ext1234
  • 1 (234) 567-8901
  • 1.234.567.8901
  • 1/234/567/8901
  • 12345678901

Responderei com minha tentativa atual, mas espero que alguém tenha algo melhor e / ou mais elegante.

Nicholas Trandem
fonte
3
BTW, você deve especificar qual idioma você está usando. Nem todos os mecanismos de expressão regular têm a mesma sintaxe.
AndrewJFord 23/09/08
9
Parece que você deixou de lado a opção +1 em vez de apenas 1, embora a resposta cubra esse caso.
Eric
153
Nem todos os números de telefone dos EUA exigem 555neles além de 911?
Andrew Grimm
41
Pelo contrário, o prefixo 555 é reservado para números de telefone falsificados. É garantido que esses números não se conectem a um número de telefone real, por isso são frequentemente usados ​​na televisão e nos filmes para garantir que um espectador não tente ligar para o número e acabe assediando alguns inocentes pobres.
rushinge
49
@rushinge Embora isso fosse verdade décadas atrás, não é mais verdade . O prefixo 555 ainda é especial, mas apenas um pequeno intervalo de números é garantido para terminar sem a conexão 555-0100 a 555-0199. Mas tenho certeza de que Andrew estava brincando de qualquer maneira.
Adam Davis

Respostas:

515

Melhor opção ... apenas retire todos os caracteres que não sejam dígitos na entrada (exceto os sinais 'x' e '+' iniciais), tendo o cuidado de manter a tendência britânica de escrever números no formato não-padrão +44 (0) ...quando solicitado a usar o prefixo internacional (nesse caso específico, você deve descartar (0)totalmente).

Então, você acaba com valores como:

 12345678901
 12345678901x1234
 345678901x1234
 12344678901
 12345678901
 12345678901
 12345678901
 +4112345678
 +441234567890

Então, quando você exibir, reformate o conteúdo do seu coração. por exemplo

  1 (234) 567-8901
  1 (234) 567-8901 x1234
scunliffe
fonte
35
O código de formatação será uma perda de tempo se os números puderem vir de fora dos EUA.
21119 Daniel Earwicker
26
Isso é bom e tudo, mas não valida o que foi digitado, na verdade, era um número de telefone. Por exemplo, e se o usuário não digitar os 10 dígitos necessários? Isso deve ser combinado com boa validação de regex.
Hugh Jeffner
108
Considerando que a pergunta era sobre validação - essa é uma resposta realmente muito ruim.
PlexQ
15
@PlexQ Eu discordo. O problema original está tentando lidar com a validação de número de telefone porque estava tentando lidar com todas as opções de formatação possíveis. Em vez de tentar resolver tudo isso, pegue a entrada e remova-a de todos os tipos de formatação até obter apenas o "número". Isso resolve dois problemas - agora é fácil testar o resultado e agora você pode garantir que os valores renderizados novamente para exibição possam ser formatados de forma consistente. O primeiro comentário desta resposta sobre as "Luvas do complicador" é uma boa leitura ... às vezes a resposta para um problema é abordá-lo de maneira diferente.
scunliffe
29
Como diabos é essa resposta altamente votada? Isso não valida nada. O pior é todas as outras questões de validação de número de telefone referenciar este ...
jlars62
303

Acontece que há uma espécie de especificação para isso, pelo menos para a América do Norte, chamada NANP .

Você precisa especificar exatamente o que deseja. O que são delimitadores legais? Espaços, traços e pontos? Nenhum delimitador permitido? Pode-se misturar delimitadores (por exemplo, + 0,1111-222,3333)? Como as extensões (por exemplo, 111-222-3333 x 44444) serão tratadas? E os números especiais, como o 911? O código de área será opcional ou obrigatório?

Aqui está uma regex para um número de 7 ou 10 dígitos, com extensões permitidas, delimitadores são espaços, traços ou pontos:

^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$
fatcat1111
fonte
7
aqui está sem a seção de extensão (eu faço meus usuários digitar ext em um campo separado): ^ (?: (?: \ +? 1 \ s * (?: [.-] \ s *)?)? (? : (\ s * ([2-9] 1 [02-9] | [2-9] [02-8] 1 | [2-9] [02-8] [02-9]) \ s *) | ([2-9] 1 [02-9] | [2-9] [02-8] 1 | [2-9] [02-8] [02-9])] \ s * (?: [ .-] \ s *)?)? ([2-9] 1 [02-9] | [2-9] [02-9] 1 | [2-9] [02-9] {2}) \ s * (?: [.-] \ s *)? ([0-9] {4}) $
aarona
18
Aqui está uma versão que corresponde apenas 10 números de telefone dígitos (não 7 dígitos como 843-1212): /(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})/
Brian Armstrong
8
10 dígitos aceitam () em torno do código de área e não permitem preceder 1 como código do país(?:(?:(\s*\(?([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\)?\s*(?:[.-]\s*)?)([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})
Brooke.
5
@StevenSoroka Eu tenho o livro de Jeffrey Friedl ao meu lado na minha mesa nos últimos dois anos, pois expressões regulares são uma parte importante do meu trabalho. Demora um bom tempo para realmente entender expressões regulares. Às vezes, os leitores deste site estão simplesmente procurando uma solução existente, em vez de escreverem seus próprios, especialmente em domínios com muitos casos de canto, como representações de números de telefone.
Justin R.
7
@ fatcat1111 Entendo isso, mas a maioria das respostas aqui são do tipo "eu também" de expressões regulares pontuais que provavelmente não se encaixam em nenhum dos seus casos de canto. Estes acabam em todos os sites que estou tentando usar e não consigo inserir meu CEP, número de telefone ou endereço de email porque alguém usou uma expressão regular meia-boca (por exemplo: + é um caractere válido nos endereços de email ) As melhores respostas nesta página apontam os usuários para bibliotecas, não para expressões regulares rabiscadas por guardanapos.
Steven Soroka
298
.*

Se os usuários quiserem fornecer seus números de telefone, confie neles para acertar. Se eles não quiserem dar a você, forçá-los a inserir um número válido os enviará ao site de um concorrente ou os fará inserir uma sequência aleatória adequada ao seu regex. Eu posso até ficar tentado a procurar o número de uma linha direta de horóscopo de tarifa premium e inserir isso.

Eu também consideraria uma das seguintes opções como entradas válidas em um site:

"123 456 7890 until 6pm, then 098 765 4321"  
"123 456 7890 or try my mobile on 098 765 4321"  
"ex-directory - mind your own business"
Dave Kirby
fonte
202
Concordo com o sentimento aqui, mas às vezes é bom executar a validação quando o número de telefone for realmente usado para algo importante no interesse do usuário . O melhor exemplo aqui é a autorização do cartão de crédito para uma compra. Se o número do telefone estiver errado, a autenticação poderá falhar.
Pointy
53
Se o usuário não quiser digitar seu número de telefone, você pode permitir que o campo seja opcional, mas é demais pedir ao usuário que digite um número de telefone válido, caso ele queira digitar um?
Joel McBeth
11
Além disso, um papel da validação é simplesmente lembrar as pessoas de adicionar códigos de área, etc., que eles não se lembrariam de acrescentar, mas que não podem ser adivinhados após o fato.
Ben McIntyre
29
@ Pointy Mas a validação de regex não irá ajudá-lo. A única maneira de validar se o número de telefone está correto é enviar uma mensagem para ele (no caso de celular) E garantir que o usuário confirme usando algum tipo de código de verificação. É isso que você faz quando a correção do número é importante. Tudo o resto é apenas para conveniência do usuário, para proteger contra alguns erros de digitação (mas não todos) e não valida nada.
Alex B
14
Legal. Meu número de telefone é 1 'OU 1 = 1 - PWNED . Veja xkcd.com/327 e owasp.org/index.php/Testing_for_SQL_Injection_(OWASP-DV-005)
Aaron Newton
171

Eu também sugeriria examinar a Biblioteca do Google " libphonenumber ". Eu sei que não é regex, mas faz exatamente o que você deseja.

Por exemplo, ele reconhecerá que:

15555555555

é um número possível, mas não é um número válido. Ele também suporta países fora dos EUA.

Destaques da funcionalidade:

  • Análise / formatação / validação de números de telefone para todos os países / regiões do mundo.
  • getNumberType- obtém o tipo do número com base no próprio número; capaz de distinguir números de telefone fixo, móvel, gratuito, tarifa premium, custo compartilhado, VoIP e pessoal (sempre que possível).
  • isNumberMatch - obtém um nível de confiança sobre se dois números podem ser iguais.
  • getExampleNumber/ getExampleNumberByType- fornece números de exemplo válidos para todos os países / regiões, com a opção de especificar qual tipo de número de telefone de exemplo é necessário.
  • isPossibleNumber - adivinhar rapidamente se um número é um número de telefone possível usando apenas as informações de comprimento, muito mais rápido que uma validação completa.
  • isValidNumber - validação completa de um número de telefone para uma região usando informações de comprimento e prefixo.
  • AsYouTypeFormatter - formata os números de telefone rapidamente quando os usuários digitam cada dígito.
  • findNumbers - encontra números na entrada de texto.
  • PhoneNumberOfflineGeocoder - fornece informações geográficas relacionadas a um número de telefone.

Exemplos

O maior problema com a validação de número de telefone é que é muito culturalmente dependente.

  • América
    • (408) 974–2042é um número americano válido
    • (999) 974–2042não é um número válido dos EUA
  • Austrália
    • 0404 999 999é um número australiano válido
    • (02) 9999 9999também é um número australiano válido
    • (09) 9999 9999não é um número australiano válido

Uma expressão regular é adequada para verificar o formato de um número de telefone, mas não será capaz de verificar a validade de um número de telefone.

Eu sugeriria pular uma expressão regular simples para testar seu número de telefone e usar uma biblioteca como a do Google libphonenumber(link para o projeto GitHub) .

Apresentando libphonenumber!

Usando um de seus exemplos mais complexos 1-234-567-8901 x1234, você obtém os seguintes dados libphonenumber(link para a demonstração online) :

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results:

E164 format                    +12345678901
Original format                (234) 567-8901 ext. 123
National format                (234) 567-8901 ext. 123
International format           +1 234-567-8901 ext. 123
Out-of-country format from US  1 (234) 567-8901 ext. 123
Out-of-country format from CH  00 1 234-567-8901 ext. 123

Portanto, você não apenas aprende se o número de telefone é válido (qual é), mas também obtém uma formatação consistente de número de telefone no seu local.

Como bônus, libphonenumberpossui vários conjuntos de dados para verificar a validade dos números de telefone, assim, verificar um número como +61299999999(a versão internacional de (02) 9999 9999) retorna como um número válido com formatação:

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     true

Formatting Results

E164 format                    +61299999999
Original format                61 2 9999 9999
National format                (02) 9999 9999
International format           +61 2 9999 9999
Out-of-country format from US  011 61 2 9999 9999
Out-of-country format from CH  00 61 2 9999 9999

O libphonenumber também oferece muitos benefícios adicionais, como escolher o local em que o número de telefone foi detectado e também obter as informações de fuso horário no número de telefone:

PhoneNumberOfflineGeocoder Results
Location        Australia

PhoneNumberToTimeZonesMapper Results
Time zone(s)    [Australia/Sydney]

Mas o número de telefone australiano inválido ( (09) 9999 9999) retorna que não é um número de telefone válido.

Validation Results

Result from isPossibleNumber()  true
Result from isValidNumber()     false

A versão do Google possui código para Java e Javascript, mas as pessoas também implementaram bibliotecas para outros idiomas que usam o conjunto de dados de números de telefone do Google i18n:

A menos que você tenha certeza de que sempre aceitará números de um código de idioma e eles sempre estarão em um formato, eu sugiro que não escreva seu próprio código para isso e use libphonenumber para validar e exibir números de telefone.

Tim Groeneveld
fonte
Observando que há agora também porta Go em: github.com/ttacon/libphonenumber
michaelhanson
Ao verificar se é um número possível, você não precisa especificar um código de país? Estou usando a versão PHP e se eu inserir um número britânico como (substitua 0 por números reais) 07700000000, recebo um Missing or invalid default region.erro. Mas se eu especificar o código do país, ele passará.
BugHunterUK
FYI: Esta biblioteca não suporta alguns países, phpinterviewquestions.co.in/blog/ionic/…
sijo vijayan
1
O @BugHunterUK (e qualquer pessoa que se depare com essa pergunta e se pergunte o mesmo) ao analisar um número, pode especificar a região esperada e a biblioteca procurará números não internacionais nessa região. Se você não especificar, ele rejeitará qualquer coisa que não esteja em um formato internacional válido.
IMSOP
Considere github.com/nyaruka/phonenumbers , pois se tornou o pacote Go "oficial" recomendado pelo Google, em vez da libphonenumber.
DeeZone
78

/^(?:(?:\(?(?:00|\+)([1-4]\d\d|[1-9]\d?)\)?)?[\-\.\ \\\/]?)?((?:\(?\d{1,}\)?[\-\.\ \\\/]?){0,})(?:[\-\.\ \\\/]?(?:#|ext\.?|extension|x)[\-\.\ \\\/]?(\d+))?$/i

Isso corresponde:

 - (+351) 282 43 50 50
 - 90191919908
 - 555-8909
 - 001 6867684
 - 001 6867684x1
 - 1 (234) 567-8901
 - 1-234-567-8901 x1234
 - 1-234-567-8901 ext1234
 - 1-234 567.89/01 ext.1234
 - 1(234)5678901x1234
 - (123)8575973
 - (0055)(123)8575973

Em $ n, ele salva:

  1. Indicador do país
  2. Número de telefone
  3. Extensão

Você pode testá-lo em https://www.regexpal.com/?fam=99127

Ismael Miguel
fonte
Este foi o regex mais abrangente que eu já vi. É fácil se locomover até você remover ^e, caso $contrário, eu posso contornar isso usando [111] [111] [1111]ou 111--111--1111e assim por diante . (desculpe, apaguei o meu último comentário)
bafromca
Você pode refazer a frase? Não consigo entender isso: "É fácil obter um arround até você remover ^ e $, ou então eu consigo contornar isso usando [111] [111] [1111]". Isso significa que ele valida '[111] [111] [1111]' quando você pega ^oe o $?
Ismael Miguel
Eu contornei seu regex usando [111] [111] [1111]e 111--111--1111até removê-lo ^e $do regex.
precisa saber é o seguinte
11
^^^ Este é um ótimo exemplo de por que os tópicos de comentários NÃO devem ir ao bate-papo. Estou muito interessado em saber como essa conversa acabou e preciso saber se esse ReGex é resistente o suficiente para usar no meu aplicativo. Infelizmente, a conversa no bate-papo acabou agora.
187148 Matt Cashatt
1
Para ser sincero, eu não fui conversar. Depois de pedir várias vezes explicações, fiquei sem informações. Você sempre pode tentar você mesmo com todos os tipos de números encontrados on-line, em vários formatos. Uma coisa que tentei com este é usar vários números de telefone, mas ele não funciona tão bem se eles têm espaços ao redor. E eu tenho que encontrar uma solução para contar a quantidade de dígitos e aplicar uma quantidade específica.
Ismael Miguel
63

Embora a resposta para remover todo o espaço em branco seja clara, ela realmente não resolve o problema apresentado, que é encontrar um regex. Pegue, por exemplo, meu script de teste que baixa uma página da web e extrai todos os números de telefone usando o regex. Como você precisaria de uma regex de qualquer maneira, é possível que ela faça todo o trabalho. Eu vim com isso:

1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?

Aqui está um script perl para testá-lo. Quando você corresponde, $ 1 contém o código de área, $ 2 e $ 3 contêm o número de telefone e $ 5 contém a extensão. Meu script de teste baixa um arquivo da Internet e imprime todos os números de telefone nele.

#!/usr/bin/perl

my $us_phone_regex =
        '1?\W*([2-9][0-8][0-9])\W*([2-9][0-9]{2})\W*([0-9]{4})(\se?x?t?(\d*))?';


my @tests =
(
"1-234-567-8901",
"1-234-567-8901 x1234",
"1-234-567-8901 ext1234",
"1 (234) 567-8901",
"1.234.567.8901",
"1/234/567/8901",
"12345678901",
"not a phone number"
);

foreach my $num (@tests)
{
        if( $num =~ m/$us_phone_regex/ )
        {
                print "match [$1-$2-$3]\n" if not defined $4;
                print "match [$1-$2-$3 $5]\n" if defined $4;
        }
        else
        {
                print "no match [$num]\n";
        }
}

#
# Extract all phone numbers from an arbitrary file.
#
my $external_filename =
        'http://web.textfiles.com/ezines/PHREAKSANDGEEKS/PnG-spring05.txt';
my @external_file = `curl $external_filename`;
foreach my $line (@external_file)
{
        if( $line =~ m/$us_phone_regex/ )
        {
                print "match $1 $2 $3\n";
        }
}

Editar:

Você pode alterar \ W * para \ s * \ W? \ S * no regex para aumentar um pouco. Eu não estava pensando no regex em termos de, digamos, validar a entrada do usuário em um formulário quando o escrevi, mas essa alteração possibilita o uso do regex para esse fim.

'1?\s*\W?\s*([2-9][0-8][0-9])\s*\W?\s*([2-9][0-9]{2})\s*\W?\s*([0-9]{4})(\se?x?t?(\d*))?';
indiv
fonte
2
Para sua informação, o regex também corresponde: o (4570457-6789que seria um erro de digitação bastante comum. Os grupos de jogos também são distorcidos: rubular.com/r/TaTP0mHL5c
SooDesuNe
A pré-adição de @SooDesuNe (^|[^\d\n])(com o sinalizador de múltiplas linhas ativado ) evita o problema geral, garantindo que ele não seja precedido imediatamente por algo numérico.
btown
Observe que isso é centralizado na América do Norte - ele perde "44 7911 123456"
Ben Wheeler
43

Respondi a essa pergunta em outra pergunta do SO antes de decidir incluir também a minha resposta como resposta neste segmento, porque ninguém estava abordando como exigir / não exigir itens, apenas distribuindo regexs: Regex funcionando errado, combinando coisas inesperadas

Na minha publicação no site, criei um guia rápido para ajudar qualquer pessoa a criar sua própria regex para o formato de número de telefone desejado, que eu vou ressaltar (como fiz no outro site) que, se você for muito restritivo, você pode não obter os resultados desejados e não existe uma solução "tamanho único" para aceitar todos os números de telefone possíveis no mundo - apenas o que você decide aceitar como seu formato de escolha. Use por sua conta e risco.

Folha de dicas rápidas

  • Inicie a expressão: /^
  • Se você deseja exigir um espaço, use: [\s]ou\s
  • Se você deseja solicitar parênteses, use: [(]e [)]. Usando \(e\) é feio e pode tornar as coisas confusas.
  • Se você quiser que algo seja opcional, coloque um ? depois
  • Se você quiser um hífen, basta digitar - ou[-] . Porém, se você não o colocar primeiro ou por último em uma série de outros personagens, poderá ser necessário escapá-lo: \-
  • Se você deseja aceitar opções diferentes em um slot, coloque colchetes entre as opções: [-.\s] exigirá um hífen, ponto ou espaço. Um ponto de interrogação após o último colchete tornará todos os opcionais para esse slot.
  • \d{3}: Requer um número de 3 dígitos: 000-999. Taquigrafia para [0-9][0-9][0-9] .
  • [2-9] : Requer um dígito 2-9 para esse slot.
  • (\+|1\s)? : Aceite um "mais" ou um 1 e um espaço (caractere de barra vertical, | , é "ou") e torne-o opcional. O sinal de "mais" deve ser escapado.
  • Se você quiser que números específicos correspondam a um slot, digite-os: [246]exigirá 2, 4 ou 6. [77|78]exigirá 77 ou 78.
  • $/ : Finalize a expressão
vapcguy
fonte
1
Isso é muito útil, mas duvido e procure por uma expressão {min, max}. Você pode ajudar?
Ataboy Josef 07/01
Se estamos falando de um único dígito (e você pode fazê-lo corresponder de acordo com isso), veja o [2-9]bloco que coloquei lá. Isso significa que seu mínimo é 2 e seu máximo é 9. Ajuste de acordo.
Vapcguy
30

Eu escrevi mais simples (embora eu não precisei de ponto).

^ ([0-9 \ (\) \ / \ + \ -] *) $

Como mencionado abaixo, ele verifica apenas caracteres, não sua estrutura / ordem

Artjom Kurapov
fonte
38
isso valida toneladas de números que são tecnicamente inválidos. como "- + () () ()) ()))"). Aprenda a ler expressões regulares para entender o que está fazendo.
Steven Soroka 28/03
3
@StevenSoroka tecnicamente ele pode permitir que muitos dos casos inválidos, mas quando pensamos apenas ajudando o usuário a evitar erros comuns com a solução mais simples possível, este é o caminho a percorrer :)
happyhardik
2
isso também corresponde a espaço em branco, linha vazia
Wasim A.
1
@HappyHardik. De fato. Simples e poderoso, para validação básica, deixe o usuário digitar mais de um ponto, traço, colchete ou mais.
585 dijipiji
Apenas usei e está errado em muitos aspectos. Por exemplo, um número de telefone no Reino Unido pode começar com +44 ou um número de telefone pode ter (0) dentro dele. Mas isso não é válido de acordo com sua expressão regular. Eu recomendaria a resposta de @Ismael Miguel. Funciona muito bem e eu recomendo que você revise sua resposta.
Stelios Voskos
22

Se você apenas deseja verificar se não possui lixo aleatório no campo (por exemplo, de spammers de formulários), este regex deve ser bem:

^[0-9+\(\)#\.\s\/ext-]+$

Observe que ele não possui regras especiais para quantos dígitos, ou quais números são válidos nesses dígitos, apenas verifica se apenas dígitos, parênteses, traços, mais, espaço, libra, asterisco, ponto, vírgula ou as letras e, x, testão presentes.

Deve ser compatível com números internacionais e formatos de localização. Você prevê alguma necessidade de permitir colchetes quadrados, encaracolados ou angulares para algumas regiões? (atualmente eles não estão incluídos).

Se você deseja manter as regras por dígito (como nos códigos de área e nos prefixos (códigos de câmbio) dos EUA, devem estar entre 200 e 999), boa sorte para você. Manter um conjunto de regras complexo que pode estar desatualizado em qualquer momento no futuro por qualquer país do mundo não parece divertido.

E, embora a exclusão de todos / a maioria dos caracteres não numéricos possa funcionar bem no servidor (especialmente se você estiver planejando passar esses valores para um discador), talvez não queira debater a entrada do usuário durante a validação, principalmente se desejar que eles faça correções em outro campo.

Steve
fonte
22

Observe que a remoção de ()caracteres não funciona para um estilo comum de escrever números do Reino Unido: o +44 (0) 1234 567890que significa discar para o número internacional
+441234567890
ou para discar para o Reino Unido.01234567890

Ben Clifford
fonte
15

Você já deu uma olhada no RegExLib ?

A inserção do número de telefone nos EUA trouxe de volta uma lista de possibilidades.

Rob Wells
fonte
3
Essa é uma ótima maneira de integrar bugs obscuros ao seu código.
Tom Lord
12

Minha tentativa de uma regex irrestrita:

/^[+#*\(\)\[\]]*([0-9][ ext+-pw#*\(\)\[\]]*){6,45}$/

Aceita:

+(01) 123 (456) 789 ext555
123456
*44 123-456-789 [321]
123456
123456789012345678901234567890123456789012345
*****++[](][((( 123456tteexxttppww

Rejeita:

mob 07777 777777
1234 567 890 after 5pm
john smith
(empty)
1234567890123456789012345678901234567890123456
911

Cabe a você higienizá-lo para exibição. Depois de validar, pode ser um número.

ReactiveRaven
fonte
12

Eu achei que isso funcionava muito bem:

^\(*\+*[1-9]{0,3}\)*-*[1-9]{0,3}[-. /]*\(*[2-9]\d{2}\)*[-. /]*\d{3}[-. /]*\d{4} *e*x*t*\.* *\d{0,4}$

Funciona para estes formatos numéricos:

1-234-567-8901
1-234-567-8901 x1234
1-234-567-8901 ext1234
1 (234) 567-8901
1.234.567.8901
1/234/567/8901
12345678901
1-234-567-8901 ext. 1234
(+351) 282 433 5050

Certifique-se de usar sinalizadores globais e multilinhas para garantir.

Link: http://www.regexr.com/3bp4b

Herobrine2Nether
fonte
11

Se você estiver falando sobre validação de formulário, a regexp para validar o significado correto e os dados corretos será extremamente complexa devido a diferentes padrões de país e provedor. Também será difícil manter-se atualizado.

Interpreto a pergunta como procurando um padrão amplamente válido, que pode não ser consistente internamente - por exemplo, ter um conjunto de números válido, mas não validar que a linha do tronco, a troca etc. para o padrão válido para o prefixo do código do país .

A América do Norte é direta e, para internacional, prefiro usar um padrão 'idiomático' que cubra as maneiras pelas quais as pessoas especificam e lembram seus números:

^((((\(\d{3}\))|(\d{3}-))\d{3}-\d{4})|(\+?\d{2}((-| )\d{1,8}){1,5}))(( x| ext)\d{1,5}){0,1}$

O padrão norte-americano garante que, se um parêntese estiver incluído, ambos estejam. As contas internacionais de um '+' inicial opcional e o código do país. Depois disso, você está no idioma. Correspondências válidas seriam:

  • (xxx)xxx-xxxx
  • (xxx)-xxx-xxxx
  • (xxx)xxx-xxxx x123
  • 12 1234 123 1 x1111
  • 12 12 12 12 12
  • 12 1 1234 123456 x12345
  • +12 1234 1234
  • +12 12 12 1234
  • +12 1234 5678
  • +12 12345678

Isso pode ser tendencioso, pois minha experiência é limitada à América do Norte, Europa e um pouco da Ásia.

ron0
fonte
Eu tenho tentado implementar o acima no meu script de validação de javascript, mas continuo recebendo um invalid quantifiererro. Alguma idéia do que estou fazendo de errado?
Jannis
Eu acrescentaria o caso trivial em que o telefone é especificado sem símbolos, mas talvez espaços e códigos de países, na Europa é típico para números locais e móveis: 676412342, 676 46 32 12, 676 463 212
rompe
11

Aqui está um padrão maravilhoso que mais se aproximava da validação que eu precisava alcançar. Não sou o autor original, mas acho que vale a pena compartilhar, pois achei esse problema muito complexo e sem uma resposta concisa ou amplamente útil.

O regex a seguir capturará combinações de números e caracteres amplamente usadas em vários formatos globais de números de telefone:

/^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/gm

Positivo:
+42 555.123.4567
+ 1- (800) -123-4567
+7 555 1234567
+7 (926) 1234567
(926) 1234567
+79261234567
926 1234567
9261234567
1234567
123-4567
123-89-01
495 1234567
469 123 45 67
89261234567
8 (926) 1234567
926.123.4567
415-555-1234
650-555-2345
(416)555-3456
202 555 4567
4035555678
1 416 555 9292

Negativo:
926 3 4
8 800 600-APPLE

Fonte original: http://www.regexr.com/38pvb

Stuart Kershaw
fonte
Isso tem algum suporte limitado para extensões. Corresponde a "616-555-1234 x567", mas não "616-555-1234 ext. 567".
Jon Schneider
2
Falso positivo para, por exemplo, "------- ((((((55555555" ou "9999999999999999999999999")
mikep:
Ele não valida Nitherland número macdonalds +31 76 596 4192 (eu estava apenas testando para números aleatórios)
BIOHAZARD
10

Meu pressentimento é reforçado pela quantidade de respostas a esse tópico - de que há um número praticamente infinito de soluções para esse problema, nenhuma das quais será elegante.

Honestamente, eu recomendaria que você não tente validar números de telefone. Mesmo se você pudesse escrever um validador grande e cabeludo que permitisse todos os diferentes formatos legítimos, isso acabaria permitindo praticamente qualquer coisa, mesmo remotamente semelhante a um número de telefone.

Na minha opinião, a solução mais elegante é validar um comprimento mínimo, nada mais.

mindplay.dk
fonte
Depois de tentar um número destes e passando os dados existentes e feedback dos usuários i tenderia a concordar ...
Christopher King
Às vezes, você precisa fazer a validação. Se estou enviando códigos de confirmação, não posso simplesmente enviar um código para qualquer lixo aleatório que um remetente de spam tenha inserido no campo. Quero garantir que o número seja provavelmente um número de telefone antes de desperdiçar recursos em enviar mensagens para ele.
Luke
10

Este é um padrão simples de expressão regular para números de telefone celular das Filipinas:

((\+[0-9]{2})|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4}

ou

((\+63)|0)[.\- ]?9[0-9]{2}[.\- ]?[0-9]{3}[.\- ]?[0-9]{4}

irá corresponder a estes:

+63.917.123.4567  
+63-917-123-4567  
+63 917 123 4567  
+639171234567  
09171234567  

O primeiro corresponderá a QUALQUER código de país com dois dígitos, enquanto o segundo corresponderá exclusivamente ao código de país das Filipinas.

Teste aqui: http://refiddle.com/1ox

GaiusSensei
fonte
Obrigado. Que tal números de telefones fixos com código de área como 028231234? Gostaria de saber se os códigos de área são apenas números de 2 a 3 dígitos e são sempre precedidos por 0?
stormwild
9

Aqui está a minha melhor tentativa até agora. Ele lida com os formatos acima, mas tenho certeza de que estou perdendo outros formatos possíveis.

^\d?(?:(?:[\+]?(?:[\d]{1,3}(?:[ ]+|[\-.])))?[(]?(?:[\d]{3})[\-/)]?(?:[ ]+)?)?(?:[a-zA-Z2-9][a-zA-Z0-9 \-.]{6,})(?:(?:[ ]+|[xX]|(i:ext[\.]?)){1,2}(?:[\d]{1,5}))?$
Nicholas Trandem
fonte
9

Você terá dificuldade em lidar com números internacionais com uma regex única / simples, consulte esta postagem sobre as dificuldades de números de telefone internacionais (e até norte-americanos).

Você deseja analisar os primeiros dígitos para determinar qual é o código do país e agir de maneira diferente com base no país.

Além disso - a lista que você forneceu não inclui outro formato comum dos EUA - deixando de fora o 1. inicial. A maioria dos telefones celulares nos EUA não exige isso, e isso começará a confundir a geração mais jovem, a menos que tenha discado internacionalmente.

Você identificou corretamente que é um problema complicado ...

-Adão

Adam Davis
fonte
Não é uma solução oferecida. É POSSÍVEL. Só porque é complicado ou complexo, não significa que você deve apenas levantar os braços.
Eric Hodonsky 29/03
7

Depois de ler essas respostas, parece que não havia uma expressão regular direta que possa analisar um monte de texto e obter números de telefone em qualquer formato (incluindo internacionais com e sem o sinal de mais).

Aqui está o que eu usei para um projeto de cliente recentemente, onde tivemos que converter todos os números de telefone em qualquer formato para tel: links.

Até o momento, ele está trabalhando com tudo o que lançou, mas se ocorrerem erros, atualizarei esta resposta.

Regex:

/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/

Função PHP para substituir todos os números de telefone por tel: links (caso alguém esteja curioso):

function phoneToTel($number) {
    $return = preg_replace('/(\+*\d{1,})*([ |\(])*(\d{3})[^\d]*(\d{3})[^\d]*(\d{4})/', '<a href="tel:$1$3$4$5">$1 ($3) $4-$5</a>', $number); // includes international
    return $return;
}
Drew Thomas
fonte
Essa expressão regular corresponde +1 1234562222222222222222222222.
Varda Elentári 13/10/2015
por que não apenas voltar?
precisa saber é o seguinte
Falso positivo para "9999999999999999999999999999999999999"
Ben Wheeler
6

Acredito que o Number :: Phone :: US e Regexp :: Common (particularmente a fonte do Regexp :: Common :: URI :: RFC2806 módulos ) Perl podem ajudar.

A pergunta provavelmente deve ser especificada com mais detalhes para explicar o objetivo de validar os números. Por exemplo, 911 é um número válido nos EUA, mas 911x não é para nenhum valor de x. Isso é para que a companhia telefônica possa calcular quando você terminar de discar. Existem várias variações sobre esse problema. Mas o seu regex não verifica a parte do código de área, o que não parece ser uma preocupação.

Como validar endereços de e-mail, mesmo se você tiver um resultado válido, não poderá saber se ele foi atribuído a alguém até que você o experimente.

Se você está tentando validar a entrada do usuário, por que não normalizar o resultado e terminar com ele? Se o usuário inserir um número que você não pode reconhecer como um número válido, salve-o como inserido ou retire caracteres indisponíveis. O módulo Number :: Phone :: Normalize Perl pode ser uma fonte de inspiração.

Jon Ericson
fonte
Vou falar um pouco sobre isso aqui e dizer que permitir o 911 como número de telefone é provavelmente uma má ideia em quase todas as aplicações desse regex. Boa captura embora.
10132 Nicholas Flynt
4

Eu trabalho para uma empresa de pesquisa de mercado e temos que filtrar esses tipos de informações o tempo todo. Você está complicando demais. Apenas retire os caracteres não alfanuméricos e verifique se há uma extensão.

Para uma análise mais aprofundada, você pode assinar um dos muitos provedores que lhe dará acesso a um banco de dados de números válidos, além de informar se são telefones fixos ou celulares, desconectados etc. Isso custa dinheiro.

Joe Phillips
fonte
Validação? 123% $) *% () $ * () # 456 * () * $ # (* ( # $ @ 8908 iria coincidir com a solução proposta.
PlexQ
1
@PlexQ 555-123-1234, 07777777777, 90210, 01/01/1901 - os usuários são criativos ao compactar lixo por meio da validação. Melhor não marcar quem realmente tem alguns dados estranhos usando validação excessivamente restritiva e dizendo que está errado.
ReactiveRaven
4

Substitua os caracteres de formatação e verifique o restante quanto à validade do telefone. Em PHP,

 $replace = array( ' ', '-', '/', '(', ')', ',', '.' ); //etc; as needed
 preg_match( '/1?[0-9]{10}((ext|x)[0-9]{1,4})?/i', str_replace( $replace, '', $phone_num );

Quebrar uma regexp complexa como essa pode ser igualmente eficaz, mas muito mais simples.

rooskie
fonte
3

Achei isso interessante. Eu não testei, mas parece que funcionaria

<?php
/*
string validate_telephone_number (string $number, array $formats)
*/

function validate_telephone_number($number, $formats)
{
$format = trim(ereg_replace("[0-9]", "#", $number));

return (in_array($format, $formats)) ? true : false;
}

/* Usage Examples */

// List of possible formats: You can add new formats or modify the existing ones

$formats = array('###-###-####', '####-###-###',
                 '(###) ###-###', '####-####-####',
                 '##-###-####-####', '####-####', '###-###-###',
                 '#####-###-###', '##########');

$number = '08008-555-555';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '123-555-555';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '1800-1234-5678';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '(800) 555-123';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}

echo "<br />";

$number = '1234567890';

if(validate_telephone_number($number, $formats))
{
echo $number.' is a valid phone number.';
}
?>
Chris
fonte
4
Sua mensagem parece indicar que você não escreveu este código. Você se importaria de citar uma fonte, por favor?
Alastair Irvine
3

Você provavelmente seria melhor usar uma entrada mascarada para isso. Dessa forma, os usuários SÓ podem digitar números e você pode formatar da maneira que achar melhor. Não tenho certeza se isso é para um aplicativo da Web, mas se houver, existe um plugin jQuery com muito clique que oferece algumas opções para fazer isso.

http://digitalbush.com/projects/masked-input-plugin/

Eles ainda abordam como mascarar as entradas de número de telefone em seu tutorial.

Abe Miessler
fonte
3

Aqui está um que funciona bem em JavaScript. Está em uma sequência porque é isso que o widget Dojo estava esperando.

Corresponde a um número NANP da América do Norte de 10 dígitos com ramal opcional. Espaços, traços e pontos são delimitadores aceitos.

"^(\\(?\\d\\d\\d\\)?)( |-|\\.)?\\d\\d\\d( |-|\\.)?\\d{4,4}(( |-|\\.)?[ext\\.]+ ?\\d+)?$"
Richard Ayotte
fonte
3

Eu estava lutando com o mesmo problema, tentando tornar minha inscrição à prova do futuro, mas esses caras me levaram na direção certa. Na verdade, não estou checando o número em si para ver se funciona ou não, apenas estou tentando garantir que uma série de números tenha sido inserida com um ramal ou não.

Na pior das hipóteses, se o usuário tivesse que extrair um número não formatado do arquivo XML, ainda assim digitaria os números no teclado numérico do telefone 012345678x5, sem motivo real para mantê-lo bonito. Esse tipo de RegEx sairia algo assim para mim:

\d+ ?\w{0,9} ?\d+
  • 01234467 extension 123456
  • 01234567x123456
  • 01234567890
Keith Wiggans
fonte
2

Minha inclinação é concordar que retire sem dígitos e apenas aceite o que há de melhor. Talvez para garantir que pelo menos alguns dígitos estejam presentes, embora isso proíba algo como um número de telefone alfabético "ASK-JAKE", por exemplo.

Algumas expressões perl simples podem ser:

@f = /(\d+)/g;
tr/0-9//dc;

Use o primeiro para manter os grupos de dígitos juntos, o que pode fornecer dicas de formatação. Use o segundo para lançar trivialmente todos os que não sejam dígitos.

É preocupante que seja necessário que haja uma pausa e depois mais teclas digitadas? Ou algo como 555-1212 (aguarde o sinal sonoro) 123?

piCookie
fonte
2
    pattern="^[\d|\+|\(]+[\)|\d|\s|-]*[\d]$" 
    validateat="onsubmit"

Deve terminar com um dígito, pode começar com (ou + ou um dígito e pode conter + - (ou)

Ian
fonte
2

Para qualquer pessoa interessada em fazer algo semelhante com os números de celular irlandeses, eis uma maneira simples de realizá-lo:

http://ilovenicii.com/?p=87

PHP


<?php
$pattern = "/^(083|086|085|086|087)\d{7}$/";
$phone = "087343266";

if (preg_match($pattern,$phone)) echo "Match";
else echo "Not match";

Há também uma solução JQuery nesse link.

EDITAR:

solução jQuery:

    $(function(){
    //original field values
    var field_values = {
            //id        :  value
            'url'       : 'url',
            'yourname'  : 'yourname',
            'email'     : 'email',
            'phone'     : 'phone'
    };

        var url =$("input#url").val();
        var yourname =$("input#yourname").val();
        var email =$("input#email").val();
        var phone =$("input#phone").val();


    //inputfocus
    $('input#url').inputfocus({ value: field_values['url'] });
    $('input#yourname').inputfocus({ value: field_values['yourname'] });
    $('input#email').inputfocus({ value: field_values['email'] }); 
    $('input#phone').inputfocus({ value: field_values['phone'] });



    //reset progress bar
    $('#progress').css('width','0');
    $('#progress_text').html('0% Complete');

    //first_step
    $('form').submit(function(){ return false; });
    $('#submit_first').click(function(){
        //remove classes
        $('#first_step input').removeClass('error').removeClass('valid');

        //ckeck if inputs aren't empty
        var fields = $('#first_step input[type=text]');
        var error = 0;
        fields.each(function(){
            var value = $(this).val();
            if( value.length<12 || value==field_values[$(this).attr('id')] ) {
                $(this).addClass('error');
                $(this).effect("shake", { times:3 }, 50);

                error++;
            } else {
                $(this).addClass('valid');
            }
        });        

        if(!error) {
            if( $('#password').val() != $('#cpassword').val() ) {
                    $('#first_step input[type=password]').each(function(){
                        $(this).removeClass('valid').addClass('error');
                        $(this).effect("shake", { times:3 }, 50);
                    });

                    return false;
            } else {   
                //update progress bar
                $('#progress_text').html('33% Complete');
                $('#progress').css('width','113px');

                //slide steps
                $('#first_step').slideUp();
                $('#second_step').slideDown();     
            }               
        } else return false;
    });

    //second section
    $('#submit_second').click(function(){
        //remove classes
        $('#second_step input').removeClass('error').removeClass('valid');

        var emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;  
        var fields = $('#second_step input[type=text]');
        var error = 0;
        fields.each(function(){
            var value = $(this).val();
            if( value.length<1 || value==field_values[$(this).attr('id')] || ( $(this).attr('id')=='email' && !emailPattern.test(value) ) ) {
                $(this).addClass('error');
                $(this).effect("shake", { times:3 }, 50);

                error++;
            } else {
                $(this).addClass('valid');
            }


        function validatePhone(phone) {
        var a = document.getElementById(phone).value;
        var filter = /^[0-9-+]+$/;
            if (filter.test(a)) {
                return true;
            }
            else {
                return false;
            }
        }

        $('#phone').blur(function(e) {
            if (validatePhone('txtPhone')) {
                $('#spnPhoneStatus').html('Valid');
                $('#spnPhoneStatus').css('color', 'green');
            }
            else {
                $('#spnPhoneStatus').html('Invalid');
            $('#spnPhoneStatus').css('color', 'red');
            }
        });

     });

        if(!error) {
                //update progress bar
                $('#progress_text').html('66% Complete');
                $('#progress').css('width','226px');

                //slide steps
                $('#second_step').slideUp();
                $('#fourth_step').slideDown();     
        } else return false;

    });


    $('#submit_second').click(function(){
        //update progress bar
        $('#progress_text').html('100% Complete');
        $('#progress').css('width','339px');

        //prepare the fourth step
        var fields = new Array(
            $('#url').val(),
            $('#yourname').val(),
            $('#email').val(),
            $('#phone').val()

        );
        var tr = $('#fourth_step tr');
        tr.each(function(){
            //alert( fields[$(this).index()] )
            $(this).children('td:nth-child(2)').html(fields[$(this).index()]);
        });

        //slide steps
        $('#third_step').slideUp();
        $('#fourth_step').slideDown();            
    });


    $('#submit_fourth').click(function(){

        url =$("input#url").val();
        yourname =$("input#yourname").val();
        email =$("input#email").val();
        phone =$("input#phone").val();

        //send information to server
        var dataString = 'url='+ url + '&yourname=' + yourname + '&email=' + email + '&phone=' + phone;  



        alert (dataString);//return false;  
            $.ajax({  
                type: "POST",  
                url: "http://clients.socialnetworkingsolutions.com/infobox/contact/",  
                data: "url="+url+"&yourname="+yourname+"&email="+email+'&phone=' + phone,
                cache: false,
                success: function(data) {  
                    console.log("form submitted");
                    alert("success");
                }
                });  
        return false;

   });


    //back button
    $('.back').click(function(){
        var container = $(this).parent('div'),
        previous  = container.prev();

        switch(previous.attr('id')) {
            case 'first_step' : $('#progress_text').html('0% Complete');
                  $('#progress').css('width','0px');
                       break;
            case 'second_step': $('#progress_text').html('33% Complete');
                  $('#progress').css('width','113px');
                       break;

            case 'third_step' : $('#progress_text').html('66% Complete');
                  $('#progress').css('width','226px');
                       break;

        default: break;
    }

    $(container).slideUp();
    $(previous).slideDown();
});


});

Fonte .

Lajos Arpad
fonte