CPF
Onze dígitos, com ou sem pontos e hífen. Para exigir a máscara completa, tire os três "?".
/^\d{3}\.?\d{3}\.?\d{3}-?\d{2}$/Limite: Confere só o formato. Não calcula os dígitos verificadores: 000.000.000-00 passa e não é um CPF válido.
Cola de regex em português: classes, âncoras, quantificadores, grupos, lookahead, flags e Unicode, com exemplos testados de CPF, CNPJ, CEP, telefone e data.
Toda a sintaxe de regex em tabelas, com um exemplo executado de verdade em cada linha, e padrões prontos para dados brasileiros (CPF, CNPJ, CEP, telefone, placa, data, moeda) com um minitestador ao lado. O sabor é o do JavaScript (ECMAScript); as diferenças para PCRE e Python estão mais abaixo.
70 itens de sintaxe e 17 exemplos prontos, no sabor JavaScript (ECMAScript). Os resultados da coluna "Exemplo" são calculados pelo seu navegador.
O que casa com um único caractere.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
. | Qualquer caractere, menos quebra de linha (com a flag s, inclui a quebra). | /a.c/ em abc a-c ac → abca-c |
\d | Dígito de 0 a 9. No JavaScript é só ASCII, igual a [0-9]. | /\d+/ em Rua 7, nº 120 → 7120 |
\D | Qualquer caractere que não seja dígito. | /\D+/ em 2026-10 → - |
\w | Letra sem acento, dígito ou sublinhado: [A-Za-z0-9_]. Não inclui ç, ã, é. | /\w+/ em ação_1 → ao_1 |
\W | O contrário de \w. Atenção: letras acentuadas entram aqui. | /\W/ em pão! → ã! |
\s | Espaço em branco: espaço, tab, quebra de linha e espaços Unicode, como o espaço não separável. | /\s+/ em a b → |
\S | Qualquer caractere que não seja espaço em branco. | /\S+/ em bom dia → bomdia |
[abc] | Um dos caracteres da lista. | /[aeiou]/ em regex → ee |
[^abc] | Qualquer caractere que não esteja na lista. | /[^0-9]/ em a1b2 → ab |
[a-z] | Faixa: qualquer caractere entre a e z. Dá para combinar: [A-Za-z0-9]. | /[a-f0-9]+/ em cor #ff8800 → cff8800 |
[\s\S] | Qualquer caractere, inclusive quebra de linha (alternativa à flag s). | /a[\s\S]b/ em a␊b → a␊b |
a|b | Alternância: a ou b. Tem a menor precedência; use grupos para delimitar. | /gato|cão/ em cão e gato → cãogato |
Não consomem caracteres: casam com uma posição no texto.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
^ | Início do texto (com a flag m, início de cada linha). | /^\d+/ em 12 ab 34 → 12 |
$ | Fim do texto (com a flag m, fim de cada linha). | /\d+$/ em 12 ab 34 → 34 |
\b | Limite de palavra: posição entre um \w e um não \w. Não funciona bem ao lado de letras acentuadas. | /\bsol\b/ em sol girassol solar → sol |
\B | Posição que não é limite de palavra. | /\Bsol/ em sol girassol → sol |
^...$ | Juntas, obrigam o texto inteiro a casar. É o que se usa para validar um campo. | /^\d{5}$/ em 12345 → 12345 |
Quantas vezes o item anterior se repete. São gulosos por padrão: pegam o máximo possível. Com ? no fim ficam preguiçosos: pegam o mínimo.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
* | Zero ou mais vezes. | /ab*/ em a ab abbb → aababbb |
+ | Uma ou mais vezes. | /ab+/ em a ab abbb → ababbb |
? | Zero ou uma vez (torna o item opcional). | /colou?r/ em color colour → colorcolour |
{3} | Exatamente 3 vezes. | /\d{3}/ em 12 345 6789 → 345678 |
{2,} | 2 vezes ou mais. | /\d{2,}/ em 1 22 333 → 22333 |
{2,4} | De 2 a 4 vezes. | /\d{2,4}/ em 1 22 55555 → 225555 |
.+ (guloso) | Pega o máximo possível e só devolve o necessário para o resto casar. | /<.+>/ em <b>oi</b> → <b>oi</b> |
.+? (preguiçoso) | Pega o mínimo possível e só avança se for preciso. | /<.+?>/ em <b>oi</b> → <b></b> |
*? | Zero ou mais, o mínimo possível. | /".*?"/ em "a" e "b" → "a""b" |
?? | Zero ou uma vez, preferindo zero. | /ab??/ em ab → a |
{2,4}? | De 2 a 4 vezes, o mínimo possível. | /\d{2,4}?/ em 55555 → 5555 |
Parênteses agrupam, capturam e permitem reutilizar o trecho casado.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
(abc) | Grupo de captura: agrupa e guarda o trecho. Os grupos são numerados a partir de 1, pela ordem do parêntese de abertura. | /(ha)+/ em hahaha! → hahaha |
(?<nome>abc) | Grupo nomeado: o trecho fica em match.groups.nome (ES2018). | /(?<ddd>\d{2}) \d{4}/ em 11 3333 → 11 3333 |
(?:abc) | Grupo não capturante: agrupa sem guardar. Use quando só precisa aplicar um quantificador ou uma alternância. | /(?:Sr|Sra)\. \w+/ em Sra. Lima → Sra. Lima |
\1 | Referência ao que o grupo 1 capturou (o mesmo texto, não o mesmo padrão). | /(\w)\1/ em passo arroz → ssrr |
\k<nome> | Referência a um grupo nomeado. | /(?<q>["']).*?\k<q>/ em 'a' "b" → 'a'"b" |
(a|b)c | Alternância limitada ao grupo. | /(quar|sex)ta/ em quarta e sexta → quartasexta |
Verificam o que vem depois ou antes sem incluir no resultado. Lookbehind existe no JavaScript desde o ES2018.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
(?=abc) | Lookahead positivo: só casa se, logo depois, vier abc. | /\d+(?= reais)/ em 10 reais e 20 dólares → 10 |
(?!abc) | Lookahead negativo: só casa se, logo depois, não vier abc. | /\b\d+\b(?! reais)/ em 10 reais e 20 dólares → 20 |
(?<=abc) | Lookbehind positivo: só casa se, logo antes, houver abc. | /(?<=R\$ )\d+/ em R$ 50 e US$ 30 → 50 |
(?<!abc) | Lookbehind negativo: só casa se, logo antes, não houver abc. | /(?<!R\$ )\b\d+/ em R$ 50 e US$ 30 → 30 |
^(?=.*\d) | Vários lookaheads no início testam condições independentes (por exemplo, "tem dígito" e "tem maiúscula"). | /^(?=.*\d)(?=.*[A-Z]).{6,}$/ em Abc123 → Abc123 |
Letras depois da barra final (/padrão/gi) ou no segundo argumento de new RegExp("padrão", "gi").
| Sintaxe | O que faz | Exemplo |
|---|---|---|
g | Global: encontra todas as correspondências, não só a primeira. Necessária em matchAll e replaceAll. | /a/g em banana → aaa |
i | Ignora maiúsculas e minúsculas. | /brasil/i em Brasil BRASIL → BrasilBRASIL |
m | Multilinha: ^ e $ passam a valer no início e no fim de cada linha. | /^\d+/m em 1 a␊2 b → 12 |
s | dotAll: o ponto passa a casar também com quebra de linha (ES2018). | /a.b/s em a␊b → a␊b |
u | Unicode: trata emojis e outros caracteres fora do plano básico como um caractere só e habilita \p{...} e \u{...}. Também torna erro os escapes inválidos. | /^.$/u em 😀 → 😀 |
y | Sticky: só casa exatamente na posição lastIndex, sem procurar adiante. Usada em analisadores léxicos. | /\d/y em 12a3 → 12 |
d | Índices: o resultado ganha a propriedade indices, com início e fim de cada grupo (ES2022). | /\d+/d em ab 42 → 42 |
v | unicodeSets: versão ampliada da flag u, com subtração (--) e interseção (&&) de classes (ES2024). Não pode ser combinada com u. | /[\p{L}--[a-z]]+/v em aÇÃo → ÇÃ |
Para casar literalmente um caractere especial, ponha uma barra invertida antes. Especiais fora de colchetes: . * + ? ^ $ { } ( ) | [ ] \ e, na forma /literal/, a barra /.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
\. | Ponto literal. Sem a barra, o ponto casa com qualquer caractere. | /\d\.\d/ em 1.5 1x5 → 1.5 |
\\ | Barra invertida literal. | /C:\\\w+/ em C:\temp → C:\temp |
\/ | Barra literal. Obrigatório na forma /literal/; em new RegExp("...") a barra não precisa de escape. | /\d{2}\/\d{2}/ em 25/12 → 25/12 |
\$ \( \) \[ \{ \* \+ \? \| | Os demais especiais, escapados do mesmo jeito. | /R\$ \d+ \(à vista\)/ em R$ 10 (à vista) → R$ 10 (à vista) |
[.+*?$] | Dentro de colchetes quase tudo é literal. Só precisam de escape: \ ] ^ (no início) e - (no meio). | /[.+*?$]/ em a+b.c → +. |
\n \r \t | Quebra de linha (LF), retorno de carro (CR) e tabulação. | /\r?\n/ em a␍␊b␊c → ␍␊␊ |
\xHH | Caractere pelo código hexadecimal de 2 dígitos. | /\x41/ em ABC → A |
\uHHHH | Caractere pelo código Unicode de 4 dígitos hexadecimais. | /\u00E7/ em açaí → ç |
\u{HHHHH} | Qualquer código Unicode, com 1 a 6 dígitos. Exige a flag u ou v. | /\u{1F600}/u em oi 😀 → 😀 |
Propriedades Unicode resolvem o que \w não resolve em português: letras acentuadas. Exigem a flag u (ou v).
| Sintaxe | O que faz | Exemplo |
|---|---|---|
\p{L} | Qualquer letra, de qualquer alfabeto, com ou sem acento. | /\p{L}+/u em ação, coração! → açãocoração |
\p{Lu} | Letra maiúscula. | /\p{Lu}/u em São Paulo, Água → SPÁ |
\p{Ll} | Letra minúscula. | /\p{Ll}+/u em Órgão → rgão |
\p{N} | Qualquer número, incluindo dígitos de outros sistemas de escrita e frações como ½. Para só dígitos decimais, \p{Nd}. | /\p{N}+/u em ab 12½ → 12½ |
\p{P} | Pontuação. | /\p{P}/u em Olá, tudo bem? → ,? |
\p{Script=Latin} | Caracteres de um sistema de escrita (aqui, o alfabeto latino). | /\p{Script=Latin}+/u em café кофе → café |
\P{L} | P maiúsculo nega: qualquer caractere que não seja letra. | /\P{L}+/u em pão-de-ló → -- |
(?<!\p{L})…(?!\p{L}) | Substituto do \b para palavras com acento: sem letra antes e sem letra depois. | /(?<!\p{L})é(?!\p{L})/u em é até café → é |
Códigos válidos no texto de troca de replace e replaceAll.
| Sintaxe | O que faz | Exemplo |
|---|---|---|
$1, $2… | Conteúdo do grupo de captura 1, 2… | /(\d{2})\/(\d{2})\/(\d{4})/ em 25/12/2026 trocando por $3-$2-$1 → 2026-12-25 |
$<nome> | Conteúdo de um grupo nomeado. | /(?<nome>\w+) (?<sobrenome>\w+)/ em Ana Souza trocando por $<sobrenome>, $<nome> → Souza, Ana |
$& | A correspondência inteira. | /\d+/g em lote 7 e 12 trocando por [$&] → lote [7] e [12] |
$` | O trecho do texto que vem antes da correspondência. | /b/ em abc trocando por [$`] → a[a]c |
$' | O trecho do texto que vem depois da correspondência. | /b/ em abc trocando por [$'] → a[c]c |
$$ | Um cifrão literal. Necessário para escrever R$ no texto de troca. | /\d+/ em 50 trocando por R$$ $& → R$ 50 |
Padrões de validação de formato, com as âncoras ^ e $. Digite no campo ou clique em uma amostra para ver se casa. Para procurar o dado no meio de um texto, tire as âncoras e use a flag g.
Onze dígitos, com ou sem pontos e hífen. Para exigir a máscara completa, tire os três "?".
/^\d{3}\.?\d{3}\.?\d{3}-?\d{2}$/Limite: Confere só o formato. Não calcula os dígitos verificadores: 000.000.000-00 passa e não é um CPF válido.
Catorze dígitos, com ou sem pontuação. É o formato tradicional; os CNPJs que já existem não mudam.
/^\d{2}\.?\d{3}\.?\d{3}\/?\d{4}-?\d{2}$/Limite: Só o formato, sem conferir os dígitos verificadores. Rejeita o CNPJ alfanumérico: para sistemas novos, use o padrão seguinte.
Formato definido pela Receita Federal (IN RFB nº 2.229/2024) para novas inscrições a partir de julho de 2026: as 12 primeiras posições aceitam letras maiúsculas e dígitos, e os 2 dígitos verificadores continuam numéricos. Aceita também o CNPJ só numérico.
/^[A-Z\d]{2}\.?[A-Z\d]{3}\.?[A-Z\d]{3}\/?[A-Z\d]{4}-?\d{2}$/Limite: Só o formato. Letras minúsculas são rejeitadas: converta para maiúsculas antes, ou acrescente a flag i.
Oito dígitos, com hífen opcional depois do quinto.
/^\d{5}-?\d{3}$/Limite: Não diz se o CEP existe: isso só uma consulta à base dos Correios responde.
DDD de dois dígitos (sem zero), o 9 inicial e mais oito dígitos. Parênteses, espaço e hífen são opcionais.
/^\(?[1-9]{2}\)? ?9\d{4}-?\d{4}$/Limite: Aceita DDDs que não existem (como 23) e parênteses desbalanceados, como "(11 91234-5678".
Celular (9 dígitos, começando por 9) ou fixo (8 dígitos, começando por 2 a 5), com DDD e +55 opcional.
/^(?:\+55 ?)?\(?[1-9]{2}\)? ?(?:9\d{4}|[2-5]\d{3})-?\d{4}$/Limite: Não cobre 0800, 0300, números de três dígitos (190) nem telefones de outros países.
Três letras e quatro dígitos, com hífen opcional.
/^[A-Z]{3}-?\d{4}$/Limite: Exige maiúsculas (acrescente a flag i para aceitar minúsculas). Não confere se a combinação foi emitida.
Três letras, um dígito, uma letra e dois dígitos, sem hífen.
/^[A-Z]{3}\d[A-Z]\d{2}$/Limite: Exige maiúsculas. Vale para a sequência usada no Brasil; outros países do Mercosul usam disposições diferentes.
Aceita os dois modelos em um padrão só.
/^(?:[A-Z]{3}-?\d{4}|[A-Z]{3}\d[A-Z]\d{2})$/Limite: Só o formato. Exige maiúsculas.
Dia de 01 a 31, mês de 01 a 12 e ano de quatro dígitos, com grupos nomeados dia, mes e ano.
/^(?<dia>0[1-9]|[12]\d|3[01])\/(?<mes>0[1-9]|1[0-2])\/(?<ano>\d{4})$/Limite: Aceita datas que não existem, como 31/02/2026 e 29/02 de anos não bissextos. Depois de casar, confira montando a data no código.
HH:MM de 00:00 a 23:59, com segundos opcionais.
/^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$/Limite: Exige dois dígitos na hora. Para aceitar "9:05", troque [01]\d por [01]?\d.
Algo, uma arroba, algo, um ponto, algo, sem espaços e com uma única arroba. É o filtro de erro de digitação, nada além disso.
/^[^\s@]+@[^\s@]+\.[^\s@]+$/Limite: Nenhuma regex prova que um e-mail existe, e a gramática completa do padrão (RFC 5322) não cabe em uma expressão legível. Este padrão aceita endereços inválidos, como [email protected]. A única validação real é enviar uma mensagem de confirmação.
Protocolo http ou https, domínio com pelo menos um ponto, porta opcional e o restante sem espaços.
/^https?:\/\/[\w-]+(\.[\w-]+)+(:\d+)?([\/?#]\S*)?$/Limite: Não aceita localhost, endereços IPv6 nem domínios com acento. No JavaScript, prefira URL.canParse(texto) ou new URL(texto) dentro de try/catch.
R$, espaço opcional, parte inteira com ou sem ponto de milhar e exatamente dois centavos depois da vírgula.
/^R\$\s?(\d{1,3}(\.\d{3})*|\d+),\d{2}$/Limite: Não aceita valores negativos nem sem centavos. O \s (e não um espaço comum) é proposital: Intl.NumberFormat e toLocaleString separam o R$ com um espaço não separável.
Palavras formadas por letras de qualquer alfabeto, separadas por um espaço, hífen ou apóstrofo. Exige a flag u.
/^\p{L}+(?:[ '-]\p{L}+)*$/uLimite: Nomes reais são mais variados do que qualquer padrão: abreviações com ponto, como "D. Pedro", são rejeitadas. Use para ajudar a pessoa, não para barrar o cadastro.
Exige a flag u, que o testador do site ainda não oferece.
Pelo menos 8 caracteres, com uma minúscula, uma maiúscula e um dígito. Cada lookahead testa uma condição.
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/Limite: Requisitos de composição não medem a força de uma senha: "Senha123" passa. Comprimento importa mais.
Cerquilha seguida de 3 ou 6 dígitos hexadecimais.
/^#(?:[0-9a-fA-F]{3}){1,2}$/Limite: Não aceita as formas com transparência (#RGBA e #RRGGBBAA). Para aceitá-las, use #(?:[0-9a-fA-F]{3,4}){1,2}.
Regex, ou expressão regular, é uma forma compacta de descrever um padrão de texto. Em vez de procurar uma palavra exata, você descreve o formato: “cinco dígitos, um hífen opcional e mais três dígitos” vira \d{5}-?\d{3}, que casa com qualquer CEP.
Uma regex serve para três coisas:
^ e $: o valor digitado tem formato de CEP?g: quais são as datas citadas neste documento?25/12/2026 por 2026-12-25 usando grupos de captura.Leia da esquerda para a direita, um item por vez, e repare no quantificador que vem logo depois de cada item. Este é o padrão de hora do guia:
^([01]\d|2[0-3]):([0-5]\d)$| Trecho | Leitura |
|---|---|
^ | início do texto |
([01]\d|2[0-3]) | grupo 1: 0 ou 1 seguido de um dígito (00 a 19), ou 2 seguido de 0 a 3 (20 a 23) |
: | dois-pontos literal |
([0-5]\d) | grupo 2: um dígito de 0 a 5 e mais um dígito (00 a 59) |
$ | fim do texto |
Sem ^ e $, o mesmo padrão acharia 23:59 dentro de 123:599. Esquecer as âncoras é o erro mais comum em validação.
Os quantificadores *, +, ? e {n,m} são gulosos: pegam o máximo de caracteres que conseguem e só devolvem o necessário para o restante do padrão casar. Com um ? depois (*?, +?, ??, {n,m}?) ficam preguiçosos e pegam o mínimo.
No texto <b>oi</b>:
| Padrão | Resultado |
|---|---|
<.+> (guloso) | <b>oi</b>, uma correspondência só |
<.+?> (preguiçoso) | <b> e </b> |
<[^>]+> (classe negada) | <b> e </b> |
A terceira forma costuma ser a melhor: diz exatamente o que pode haver entre os sinais e não depende de tentativa e erro do motor.
(…) captura. O trecho fica disponível como $1 na substituição e como match[1] no código.(?<nome>…) captura com nome: match.groups.nome e $<nome>. Deixa o código legível quando há vários grupos, como em uma data.(?:…) só agrupa, sem capturar. Use quando o parêntese serve apenas para aplicar um quantificador ou limitar uma alternância.Para inverter uma data no JavaScript:
'25/12/2026'.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$2-$1'); // "2026-12-25"| Flag | Nome | Desde |
|---|---|---|
g | global | sempre |
i | ignorar maiúsculas e minúsculas | sempre |
m | multilinha | sempre |
s | dotAll | ES2018 |
u | Unicode | ES2015 |
y | sticky | ES2015 |
d | índices (hasIndices) | ES2022 |
v | unicodeSets | ES2024 |
Um cuidado com a flag g: um objeto RegExp global guarda a posição da última busca em lastIndex. Chamar re.test(texto) duas vezes seguidas com a mesma regex pode devolver true e depois false. Para validar, não use g.
\w e \bNo JavaScript, \w equivale a [A-Za-z0-9_] e \d a [0-9], mesmo com a flag u. Letras como ç, ã e é não são \w. Por isso \w+ aplicado a “ação” encontra a e o, e \b enxerga “limites de palavra” no meio de palavras acentuadas.
A saída é usar propriedades Unicode com a flag u:
\p{L} para qualquer letra, com ou sem acento;[\p{L}\p{N}_] como um \w que entende português;(?<!\p{L})palavra(?!\p{L}) no lugar de \bpalavra\b.Regex não é uma linguagem única. O que funciona no JavaScript pode falhar no PHP (PCRE), no Python ou no grep.
| Recurso | JavaScript | PCRE e Python |
|---|---|---|
| Grupo nomeado | (?<nome>…) | Python usa (?P<nome>…); PCRE aceita as duas formas |
| Referência na substituição | $1, $<nome> | Python usa \1 e \g<nome> |
\d e \w | sempre ASCII | no Python 3, em texto, incluem dígitos e letras Unicode por padrão |
$ sem a flag m | só no fim absoluto do texto | também casa antes de uma quebra de linha final |
\A e \Z | não existem; use ^ e $ sem a flag m | existem |
(?i) no início do padrão | não existe; use a flag i | existe |
Quantificador possessivo a++ e grupo atômico (?>…) | não existem | existem no PCRE e, desde a versão 3.11, no Python |
| Lookbehind | de qualquer comprimento | no Python, só de largura fixa |
\p{L} | com a flag u ou v | existe no PCRE; o módulo re do Python não tem |
Modo comentado (flag x) | não existe | existe |
Um detalhe traiçoeiro: sem a flag u, o JavaScript não reclama de escapes desconhecidos. \A vira a letra “A” e \p{L} vira o texto p{L}, sem nenhum erro. Com u, as duas formas dão erro de sintaxe, o que ajuda a pegar o engano cedo.
Os exemplos prontos conferem o formato do dado. Nenhum deles garante que o dado é verdadeiro:
000.000.000-00 tem formato de CPF e é inválido. Use o Validador de CPF e o Validador de CNPJ.\d{14}) passa a rejeitar empresas reais.31/02/2026. Depois de casar, monte a data no código e confira.URL.canParse() ou new URL() entendem casos que nenhuma regex curta cobre.Padrões com repetição dentro de repetição, como (a+)+$ ou (\w+\s?)+$, podem levar um tempo exponencial em entradas que quase casam. Esse problema tem nome, ReDoS, e já derrubou serviços grandes. Para evitar: prefira classes negadas ([^"]*) a .*, não aninhe quantificadores sobre trechos que podem casar com o mesmo texto e limite o tamanho da entrada antes de aplicar a regex.
git grep e git log --grep aceitam regexÉ a abreviação de regular expression, expressão regular: uma sequência de caracteres que descreve um padrão de busca em texto. Em português também aparece como “ER” ou “expressão regular”.
Para o formato com máscara: ^\d{3}\.\d{3}\.\d{3}-\d{2}$. Para aceitar com ou sem pontuação: ^\d{3}\.?\d{3}\.?\d{3}-?\d{2}$. As duas conferem só o formato; os dígitos verificadores precisam ser calculados no código.
Quase sempre por um destes motivos: o sabor é outro (veja a tabela de diferenças); dentro de uma string, a barra invertida precisa ser dobrada ("\\d+" em new RegExp, ou uma raw string r"\d+" no Python); ou faltou uma flag, como g, m ou u.
.* e .*?.* é guloso e avança até o fim da linha antes de recuar; .*? é preguiçoso e para na primeira oportunidade. Em "a" e "b", o padrão ".*" casa com o texto inteiro, e ".*?" casa com "a" e com "b" separadamente.
/?Na forma literal do JavaScript, sim: /\d{2}\/\d{2}/. Em new RegExp("\\d{2}/\\d{2}") a barra não precisa de escape, mas as barras invertidas precisam ser dobradas. Os exemplos deste guia trazem \/, que funciona nas duas formas.
Dá para filtrar erros de digitação, e é só. A gramática completa de endereços (RFC 5322) é complexa demais para uma expressão legível, e mesmo um endereço bem formado pode não existir. Use um padrão simples e confirme enviando uma mensagem.