Dev Tools

Como Validar e Formatar Telefones e Celulares no Brasil com Regex

Aprenda as regras oficiais da Anatel para validação de telefones fixos e celulares no Brasil. Padrões de Regex, validação de DDDs e exemplos prontos em TypeScript e Python.

31 de agosto de 20266 min de leituraDevThru

Validar e formatar números de telefone no Brasil é um dos desafios mais comuns em cadastros, checkouts e formulários de autenticação via SMS/WhatsApp. Embora pareça uma tarefa simples, o sistema telefônico brasileiro possui regras rígidas estabelecidas pela Anatel, envolvendo DDDs geográficos, o nono dígito obrigatório para celulares e a diferenciação entre linhas móveis e fixas.

Neste guia prático, vamos entender a anatomia dos números de telefone no Brasil, como validar DDDs reais, aplicar máscaras dinâmicas e implementar expressões regulares (Regex) robustas em JavaScript/TypeScript e Python.

1. A Anatomia do Telefone no Brasil

Um número de telefone brasileiro completo no padrão internacional (E.164) é composto por três partes:

  1. DDI (Código do País): +55 para o Brasil.
  2. DDD (Código de Área Nacional): 2 dígitos (de 11 a 99, com lacunas que não existem).
  3. Número do Assinante:
    • Telefonia Móvel (Celular): 9 dígitos (ex: 9XXXX-XXXX). O primeiro dígito é sempre o número 9, e o segundo dígito varia entre 6, 7, 8 ou 9.
    • Telefonia Fixa: 8 dígitos (ex: [2-5]XXX-XXXX). O primeiro dígito começa entre 2 e 5.
💡 Dica Importante: Celulares no Brasil sempre têm 11 dígitos no total (2 do DDD + 9 do número), enquanto telefones fixos possuem 10 dígitos no total (2 do DDD + 8 do número).

2. Lista de DDDs Válidos no Brasil

Nem todas as combinações de dois dígitos são DDDs válidos. Existem exatamente 67 DDDs ativos no Brasil divididos por regiões:

Região Estados DDDs Válidos
Sudeste SP, RJ, MG, ES 11 a 19 (SP), 21, 22, 24 (RJ), 27, 28 (ES), 31 a 35, 37, 38 (MG)
Sul PR, SC, RS 41 a 46 (PR), 47 a 49 (SC), 51, 53 a 55 (RS)
Centro-Oeste DF, GO, TO, MT, MS 61 (DF/GO), 62, 64 (GO), 63 (TO), 65, 66 (MT), 67 (MS)
Nordeste BA, SE, PE, AL, PB, RN, CE, PI, MA 71, 73 a 75, 77 (BA), 79 (SE), 81, 87 (PE), 82 (AL), 83 (PB), 84 (RN), 85, 88 (CE), 86, 89 (PI), 98, 99 (MA)
Norte PA, AM, RR, AP, AC, RO 91, 93, 94 (PA), 92, 97 (AM), 95 (RR), 96 (AP), 68 (AC), 69 (RO)

3. Expressão Regular (Regex) para Validação Completa

Abaixo está o padrão Regex rigoroso que aceita números com ou sem pontuação (parênteses, espaços e hifens), aceitando tanto telefones fixos (8 dígitos) quanto celulares com o 9º dígito obrigatório:


// Aceita formatos: (11) 99999-9999, 11999999999, (11) 3333-3333, 1133333333
const PHONE_BR_REGEX = /^(?:(?:+|00)?55s?)?(?:(?([1-9][0-9]))?s?)?(?:((?:9d|[2-5])d{3})-?(d{4}))$/;

4. Implementação em TypeScript / JavaScript

A função abaixo limpa caracteres não numéricos, valida a existência do DDD e formata o número com a máscara correta:


const VALID_DDDS = new Set([
  11, 12, 13, 14, 15, 16, 17, 18, 19,
  21, 22, 24, 27, 28,
  31, 32, 33, 34, 35, 37, 38,
  41, 42, 43, 44, 45, 46, 47, 48, 49,
  51, 53, 54, 55,
  61, 62, 63, 64, 65, 66, 67, 68, 69,
  71, 73, 74, 75, 77, 79,
  81, 82, 83, 84, 85, 86, 87, 88, 89,
  91, 92, 93, 94, 95, 96, 97, 98, 99
]);

export function validateAndFormatPhone(phone: string): { isValid: boolean; formatted: string; type?: 'mobile' | 'landline' } {
  // Remove tudo que não for dígito
  let clean = phone.replace(/\D/g, '');

  // Remove DDI 55 inicial se existir
  if (clean.length > 11 && clean.startsWith('55')) {
    clean = clean.substring(2);
  }

  // Celular (11 dígitos) ou Fixo (10 dígitos)
  if (clean.length !== 10 && clean.length !== 11) {
    return { isValid: false, formatted: phone };
  }

  const ddd = parseInt(clean.substring(0, 2), 10);
  if (!VALID_DDDS.has(ddd)) {
    return { isValid: false, formatted: phone };
  }

  const numberPart = clean.substring(2);

  // Validação de Celular: 9 dígitos iniciando com 9 e segundo dígito [6-9]
  if (clean.length === 11) {
    if (numberPart[0] !== '9' || !['6', '7', '8', '9'].includes(numberPart[1])) {
      return { isValid: false, formatted: phone };
    }
    const formatted = `(${ddd}) ${numberPart.substring(0, 5)}-${numberPart.substring(5)}`;
    return { isValid: true, formatted, type: 'mobile' };
  }

  // Validação de Fixo: 8 dígitos iniciando com [2-5]
  if (!['2', '3', '4', '5'].includes(numberPart[0])) {
    return { isValid: false, formatted: phone };
  }
  const formatted = `(${ddd}) ${numberPart.substring(0, 4)}-${numberPart.substring(4)}`;
  return { isValid: true, formatted, type: 'landline' };
}

5. Implementação em Python

Para pipelines de backend ou rotinas de limpeza de dados em Python:


import re

VALID_DDDS = {
    11, 12, 13, 14, 15, 16, 17, 18, 19,
    21, 22, 24, 27, 28,
    31, 32, 33, 34, 35, 37, 38,
    41, 42, 43, 44, 45, 46, 47, 48, 49,
    51, 53, 54, 55,
    61, 62, 63, 64, 65, 66, 67, 68, 69,
    71, 73, 74, 75, 77, 79,
    81, 82, 83, 84, 85, 86, 87, 88, 89,
    91, 92, 93, 94, 95, 96, 97, 98, 99
}

def validate_brazilian_phone(phone_str: str) -> dict:
    digits = re.sub(r'\D', '', phone_str)
    
    if len(digits) > 11 and digits.startswith('55'):
        digits = digits[2:]
        
    if len(digits) not in (10, 11):
        return {"valid": False, "error": "Tamanho de dígitos inválido"}
        
    ddd = int(digits[:2])
    if ddd not in VALID_DDDS:
        return {"valid": False, "error": f"DDD {ddd} inexistente no Brasil"}
        
    number = digits[2:]
    
    if len(digits) == 11:
        if number[0] != '9' or number[1] not in '6789':
            return {"valid": False, "error": "Celular deve iniciar com 9 seguido de [6-9]"}
        formatted = f"({ddd}) {number[:5]}-{number[5:]}"
        return {"valid": True, "formatted": formatted, "type": "mobile", "e164": f"+55{digits}"}
        
    # Telefone fixo (10 dígitos)
    if number[0] not in '2345':
        return {"valid": False, "error": "Telefone fixo deve iniciar com [2-5]"}
    formatted = f"({ddd}) {number[:4]}-{number[4:]}"
    return {"valid": True, "formatted": formatted, "type": "landline", "e164": f"+55{digits}"}

6. Gerando Números Válidos para Testes em Staging

Se você precisa de números de celular ou fixo matematicamente válidos por estado para popular seus testes automatizados no Cypress, Playwright ou Selenium sem usar números de pessoas reais, utilize o nosso Gerador de Telefone Online no DevThru.

🛠️ Experimente na prática

Use nossas ferramentas online gratuitas — sem cadastro, direto no navegador.

TelefoneCelularRegexTypeScriptPythonAnatelValidação

Esse artigo foi útil para você?