A expressão regular que recebo mais feedback, para não mencionar relatórios de “bugs”, é a que encontrará directamente na página inicial deste site: \b+@+\b. Esta expressão regular, eu reivindico, corresponde a qualquer endereço de correio electrónico. A maior parte do feedback que recebo é refutado ao mostrar um endereço de correio electrónico que este regex não corresponde. Normalmente, o relatório “bug” inclui também uma sugestão para tornar o regex “perfeito”.
Como explico abaixo, a minha alegação só é válida quando se aceita a minha definição do que é realmente um endereço de correio electrónico válido, e do que não é. Se quiser utilizar uma definição diferente, terá de adaptar o regex. A correspondência de um endereço de correio electrónico válido é um exemplo perfeito que mostra que (1) antes de escrever um regex, tem de saber exactamente o que está a tentar combinar, e o que não está; e (2) há frequentemente uma troca entre o que é exacto, e o que é prático.
A virtude da minha expressão regular acima é que corresponde a 99% dos endereços de correio electrónico em uso hoje em dia. Todos os endereços de correio electrónico que correspondem podem ser tratados por 99% de todo o software de correio electrónico que existe. Se estiver à procura de uma solução rápida, basta ler o parágrafo seguinte. Se quiser conhecer todas as compensações e obter muitas alternativas para escolher, leia em.
Se quiser usar a expressão regular acima, há duas coisas que precisa de compreender. Primeiro, longos regexes tornam difícil formatar bem os parágrafos. Assim, não incluí a-z em nenhuma das três classes de caracteres. Este regex destina-se a ser utilizado com a opção “case insensitive” do seu motor regex ligado. (Ficaria surpreendido com a quantidade de relatórios de “erros” que recebo sobre isso.) Em segundo lugar, o regex acima é delimitado com limites de palavras, o que o torna adequado para extrair endereços de correio electrónico de ficheiros ou blocos de texto maiores. Se quiser verificar se o utilizador digitou um endereço de correio electrónico válido, substitua os limites das palavras por âncoras de início e fim de linha, desta forma: ^+@+\.{2,}$.
O parágrafo anterior também se aplica a todos os exemplos seguintes. Poderá ser necessário alterar os limites das palavras em âncoras de início/fim de corda, ou vice-versa. E tem de activar a opção de correspondência insensível ao caso.
Trade-Offs na Validação de Endereços de Email
Antes de a ICANN ter tornado possível a qualquer empresa bem financiada a criação dos seus próprios domínios de topo, os domínios de topo mais longos eram os raramente utilizados .museum e .travel, que têm 6 letras. Os domínios de nível superior mais comuns tinham 2 letras para domínios específicos de cada país, e 3 ou 4 letras para domínios de uso geral como .com e .info. Muitos regexes para validação de endereços de correio electrónico que encontrará em vários tutoriais e referências regex ainda assumem que o domínio de nível superior é bastante curto. Edições mais antigas deste tutorial regex mencionaram \b+@+\b como o regex para endereços de correio electrónico na sua introdução. Há apenas uma pequena diferença entre esta regex e a que se encontra no topo desta página. O 4 no final da regex restringe o domínio de nível superior a 4 caracteres. Se utilizar este regex com âncoras para validar o endereço de e-mail introduzido no seu formulário de encomenda, [email protected] tem de fazer as suas compras noutro local. Sim, o TLD .solutions existe e quando escrevo isto, desaprovado.solutions pode ser seu por $16,88 por ano.
Se quiser ser mais rigoroso que {2,} para o domínio de nível superior, ^+@+\.{2,63}$ é o mais longe que pode praticamente ir. Cada parte de um nome de domínio não pode ter mais do que 63 caracteres. Não há domínios de nível superior de um só dígito e nenhum contém dígitos. Também não parece que a ICANN aprove tais domínios.
Endereços de e-mail podem estar em servidores de um subdomínio como em [email protected]. Todos os regexes acima correspondem a este endereço de correio electrónico, porque incluí um ponto na classe de caracteres após o símbolo @. Mas os regexes acima também coincidem com john@aol…com, que não é válido devido aos pontos consecutivos. Pode excluir tais correspondências substituindo +\. por (?:+\.)+ em qualquer um dos regexes acima indicados. Retirei o ponto da classe de caracteres e em vez disso repeti a classe de caracteres e o seguinte ponto literal. Por exemplo, ^+@(?:+\.)+{2,}$ corresponde a [email protected] mas não a john@aol…com.
Se quiser evitar que o seu sistema se engasgue com entradas arbitrariamente grandes, pode substituir os quantificadores infinitos por finitos. ^{1,64}@(?:{1,63}\.){1,125}{2,63}$ tem em conta que a parte local (antes do @) é limitada a 64 caracteres e que cada parte do nome de domínio é limitada a 63 caracteres. Não há limite directo para o número de subdomínios. Mas o comprimento máximo de um endereço de correio electrónico que pode ser tratado pela SMTP é de 254 caracteres. Assim, com uma parte local de um único caractere, um domínio de duas letras de nível superior e sub-domínios de um único caractere, 125 é o número máximo de sub-domínios.
A anterior regex não limita efectivamente os endereços de correio electrónico a 254 caracteres. Se cada parte estiver no seu comprimento máximo, o regex pode corresponder a cadeias de até 8129 caracteres de comprimento. É possível reduzir isso reduzindo o número de sub-domínios permitidos de 125 para algo mais realista como 8. Nunca vi um endereço de correio electrónico com mais de 4 sub-domínios. Se quiser aplicar o limite de 254 caracteres, a melhor solução é verificar o comprimento da cadeia de entrada antes mesmo de utilizar um regex. Embora isto exija algumas linhas de código de procedimento, verificar o comprimento de uma cadeia de caracteres é quase instantâneo. Se só puder usar regexes, ^{6,254}$ pode ser usado como primeira passagem para garantir que a cadeia de caracteres não contém caracteres inválidos e não é demasiado curta ou demasiado longa. Se precisar de fazer tudo com um regex, precisará de um sabor regex que suporte lookahead. A expressão regular ^(?={6,254}$){1,64}@(?:{1,63}}}{1,8}{2,63}$ utiliza uma lookahead para verificar primeiro se a corda não contém caracteres inválidos e não é demasiado curta ou demasiado comprida. Quando o lookahead tem êxito, o resto do regex faz uma segunda passagem sobre a corda para verificar a colocação correcta do sinal @ e dos pontos.
Todos estes regexes permitem os caracteres ._%+- em qualquer parte da parte local. Pode forçar a parte local a começar com uma letra usando ^{0,63} em vez de ^{1,64} para a parte local: ^{0,63}@(?:{1,63}\.){1,125}{2,63}$. Ao utilizar o lookahead para verificar o comprimento total do endereço, o primeiro caracter pode ser verificado no lookahead. Não é necessário repetir a verificação inicial dos caracteres ao verificar o comprimento da parte local. Esta regex é demasiado longa para caber na largura da página, por isso vamos ligar o modo de espaçamento livre:
^(?={5,253}$)
{1,64}@(?:{1,63}\.){1,8}{2,63}$
Nomes de domínio podem conter hífenes. Mas eles não podem começar ou terminar com um hífen. (?:{0,62})? corresponde a um nome de domínio entre 1 e 63 caracteres que começa e termina com uma letra ou dígito. O grupo não-capturador torna o meio do domínio e a letra ou dígito final opcional como um todo para garantir que permitimos domínios com um único caractere, ao mesmo tempo que garantimos que os domínios com dois ou mais caracteres não terminam com um hífen. O regex global começa a tornar-se bastante complicado:
^{0,63}@
(?:(?:{0,62})?\ {1,8}{2,63}$
Nomes de domínio não podem conter hífenes consecutivos. +(?:-+)* corresponde a um nome de domínio que começa e termina com uma letra ou dígito e que contém qualquer número de hífenes não consecutivos. Esta é a forma mais eficiente. Este regex não faz qualquer recuo para corresponder a um nome de domínio válido. Corresponde a todas as letras e algarismos no início do nome de domínio. Se não houver hífenes, o grupo opcional que se segue falha imediatamente. Se houver hífenes, o grupo corresponde a cada hífen seguido de todas as letras e dígitos até ao hífen seguinte ou até ao fim do nome de domínio. Não podemos impor o comprimento máximo quando os hífenes devem ser emparelhados com uma letra ou dígito, mas as letras e os dígitos podem ficar por si próprios. Mas podemos utilizar a técnica lookahead que utilizámos para impor o comprimento total do endereço de correio electrónico para impor o comprimento do nome de domínio, ao mesmo tempo que proibimos hífenes consecutivos: (?={1,63}\.)+(?:-+)*. Note-se que o lookahead também verifica o ponto que deve aparecer após o nome de domínio quando este é totalmente qualificado num endereço de correio electrónico. Isto é importante. Sem verificar o ponto, o lookahead aceitaria nomes de domínio mais longos. Uma vez que o lookahead não consome o texto que corresponde, o ponto não é incluído na correspondência global desta regex. Quando colocarmos este regex no regex global para endereços de e-mail, o ponto será igualado como era no regex anterior:
^{0,63}@
(?:(?={1,63}\.)+(?:-+)*\.){1,8}{2,63}$
Se incluirmos o lookahead para verificar o comprimento total, o nosso regex faz duas passagens sobre a parte local, e três passagens sobre os nomes de domínio para validar tudo:
^(?={5,253}$){1,64}@
(?:(?={1,63}\.)+(?:-+)*\.){1,8}{2,63}$
Num PC ou servidor moderno, este regex funcionará muito bem quando validar um único endereço de e-mail com 254 caracteres. Rejeitar entradas mais longas seria ainda mais rápido porque o regex falhará quando o lookahead falhar durante a primeira passagem. Mas não recomendaria utilizar um regex tão complexo como este para pesquisar endereços de correio electrónico através de um grande arquivo de documentos ou correspondência. É melhor usar o simples regex no topo desta página para reunir rapidamente tudo o que se parece com um endereço de correio electrónico. Deduza os resultados e depois utilize um regex mais estrito se quiser filtrar mais endereços inválidos.
E por falar em retrocesso, nenhum dos regexes desta página faz qualquer retrocesso para corresponder a endereços de correio electrónico válidos. Mas particularmente estes últimos podem fazer um pouco de backtracking em algo que não é bem um endereço de correio electrónico válido. Se o seu sabor regex suporta quantificadores possessivos, pode eliminar todos os retrocessos, tornando todos os quantificadores possessivos. Uma vez que não é necessário retroceder para encontrar resultados, fazer isto não altera o que é igualado por estes regexes. Só lhes permite falhar mais rapidamente quando a entrada não é um endereço de correio electrónico válido. O nosso regex mais simples torna-se então ^++@+++\.{2,}+$ com um + extra após cada quantificador. Podemos fazer o mesmo com o nosso regex mais complexo:
^(?={5,253}+$){1,64}+@
(?:(?={1,63}+\.)++(?:-+++)*+\.){1,8}+{2,63}+$
Uma importante contrapartida em todos estes regexes é que só permitem letras, dígitos, e os símbolos especiais mais comummente utilizados. A principal razão é que não confio em todo o meu software de e-mail para poder lidar com muito mais. Apesar de John.O’[email protected] ser um endereço de correio electrónico sintacticamente válido, existe o risco de algum software interpretar mal o apóstrofo como uma citação delimitadora. Inserir cegamente este endereço de correio electrónico numa consulta SQL, por exemplo, fará com que na melhor das hipóteses falhe quando as strings são delimitadas com aspas simples e, na pior das hipóteses, abrirá o seu sítio até ataques de injecção SQL.
E, claro, já passaram muitos anos que os nomes de domínio podem incluir caracteres não-ingleses. Mas a maioria do software ainda se cola aos 37 caracteres a que os programadores ocidentais estão habituados. O apoio a domínios internacionalizados abre uma lata inteira de vermes de como os caracteres não-ASCII devem ser codificados. Assim, se utilizar qualquer um dos regexes desta página, qualquer pessoa com um endereço @ทีเอชนิค.ไทย ficará sem sorte. Mas talvez esteja a dizer que http://ทีเอชนิค.ไทย simplesmente redirecciona para http://thnic.co.th mesmo estando no negócio de venda de domínios .ไทย.
A conclusão é que para decidir qual a expressão regular a utilizar, quer esteja a tentar corresponder a um endereço de correio electrónico ou a algo vagamente definido, tem de começar por considerar todas as contrapartidas. Quão mau é corresponder a algo que não é válido? Até que ponto é mau não corresponder a algo que é válido? Quão complexa pode ser a sua expressão regular? Quão caro seria se tivesse de mudar a expressão regular mais tarde porque se revelou ser demasiado ampla ou demasiado estreita? Respostas diferentes a estas questões exigirão uma expressão regular diferente como solução. O meu e-mail regex faz o que eu quero, mas pode não fazer o que você quer.
Regexes Don’t Send Email
Não exagere ao tentar eliminar endereços de e-mail inválidos com a sua expressão regular. A razão é que não sabe realmente se um endereço é válido até tentar enviar um e-mail para ele. E mesmo isso pode não ser suficiente. Mesmo que o e-mail chegue a uma caixa de correio, isso não significa que alguém ainda leia essa caixa de correio. Se precisar realmente de ter a certeza de que um endereço de correio electrónico é válido, terá de lhe enviar um correio electrónico que contenha um código ou link para que o destinatário execute uma segunda etapa de autenticação. E se o estiver a fazer, então faz pouco sentido utilizar um regex que pode rejeitar endereços de correio electrónico válidos.
O mesmo princípio aplica-se em muitas situações. Ao tentar combinar uma data válida, é muitas vezes mais fácil usar um pouco de aritmética para verificar se há anos bissextos, em vez de tentar fazê-lo num regex. Utilizar uma expressão regular para encontrar potenciais correspondências ou verificar se a entrada utiliza a sintaxe adequada, e fazer a validação real sobre as correspondências potenciais devolvidas pela expressão regular. As expressões regulares são uma ferramenta poderosa, mas estão longe de ser uma panaceia.
O Padrão Oficial: RFC 5322
Talvez esteja a perguntar-se por que razão não existe um regex “oficial” à prova de tolos para corresponder a endereços de correio electrónico. Bem, existe uma definição oficial, mas dificilmente é à prova de tolos.
O padrão oficial é conhecido como RFC 5322. Descreve a sintaxe a que os endereços de correio electrónico válidos devem aderir. Pode (mas não deve continuar a ler) implementá-la com a seguinte expressão regular. A RFC 5322 deixa a parte do nome de domínio aberta a escolhas específicas de implementação que não funcionarão na Internet hoje em dia. O regex implementa a sintaxe “preferida” do RFC 1035 que é uma das recomendações do RFC 5322:
\A(?:+(?:\.+)*
| “(?:
| \\\ *”)
@ (?:(?(?:*:*)?¿(?:*)?+(?:*)?br>|br>| |2|???){3}
(?:25|2|??|*:*br>(?:
||br>| {\i})+)
]){z
p>Este regex tem duas partes: a parte antes do @, e a parte depois do @. Há duas alternativas para a parte antes do @. A primeira alternativa permite que seja constituída por uma série de letras, dígitos e certos símbolos, incluindo um ou mais pontos. No entanto, os pontos podem não aparecer consecutivamente ou no início ou fim do endereço de correio electrónico. A outra alternativa exige que a parte antes do @ seja incluída entre aspas duplas, permitindo qualquer sequência de caracteres ASCII entre as aspas. Os caracteres do espaço em branco, aspas duplas e barras invertidas têm de ser evitados com barras invertidas.
A parte após o @ também tem duas alternativas. Pode ser um nome de domínio totalmente qualificado (por exemplo, regular-expressions.info), ou pode ser um endereço de Internet literal entre parênteses rectos. O endereço literal da Internet pode ser ou um endereço IP, ou um endereço de encaminhamento específico do domínio.
A razão pela qual não se deve utilizar este regex é que é excessivamente amplo. A sua aplicação pode não ser capaz de lidar com todos os endereços de correio electrónico que este regex permite. Os endereços de encaminhamento específicos do domínio podem conter caracteres de controlo ASCII não imprimíveis, o que pode causar problemas se a sua aplicação necessitar de exibir endereços. Nem todas as aplicações suportam a sintaxe da parte local utilizando aspas duplas ou parênteses rectos. De facto, o próprio RFC 5322 marca a notação usando parênteses rectos como obsoleta.
Obtém-se uma implementação mais prática do RFC 5322 se omitirmos endereços IP, endereços específicos de domínio, a sintaxe usando aspas duplas e parênteses rectos. Continuará a corresponder a 99,99% de todos os endereços de correio electrónico em uso real hoje.
\A+(?:\.+)*@@br>(?:(?:*)?\.)+(?:*)?\z
Nenhum destes regexes impõe limites de comprimento no endereço de correio electrónico global ou na parte local ou nos nomes de domínio. O RFC 5322 não especifica quaisquer limites de comprimento. Estas decorrem de limitações noutros protocolos como o protocolo SMTP para o envio efectivo de correio electrónico. O RFC 1035 declara que os domínios devem ter 63 caracteres ou menos, mas não inclui isso na sua especificação de sintaxe. A razão é que uma verdadeira linguagem regular não pode impor um limite de comprimento e proibir hífenes consecutivos ao mesmo tempo. Mas os sabores regex modernos não são verdadeiramente regulares, por isso podemos adicionar verificações de limite de comprimento usando lookahead como fizemos antes:
\A(?={6,254}\z)
(?={1,64}@)
+(?:\.+)*
@ (?:(?={1,63}\\.)(?:*)?\.)+
(?={1,63}\z)(?:*)?\z
Assim, mesmo quando se seguem os padrões oficiais, ainda há compensações a fazer. Não copie cegamente expressões regulares de bibliotecas em linha ou fóruns de discussão. Teste-as sempre com os seus próprios dados e com as suas próprias aplicações.
Faça um Donativo
Guardar uma viagem até à livraria? Faça um donativo para apoiar este sítio, e terá uma vida inteira de acesso livre de publicidade a este sítio!