Letra do DNI e do NIE espanhóis: algoritmo e código
Como se calcula a letra do DNI e do NIE espanhóis (módulo 23), com código em JavaScript, PHP e Python, casos-limite e porque uma letra certa não prova nada.
Por Equipa Constaia5 min de leitura
Em Espanha, os cidadãos têm o DNI (Documento Nacional de Identidad): oito algarismos e uma letra de controlo, por exemplo 12345678Z. Os estrangeiros residentes têm o NIE (Número de Identidad de Extranjero): uma letra inicial X, Y ou Z, sete algarismos e uma letra de controlo. Ambos funcionam como número de identificação fiscal (NIF) espanhol, por isso aparecem em quase todos os formulários: inscrições, faturas, licenças desportivas. Se a sua plataforma recebe participantes ou clientes espanhóis, vai encontrá-los.
A letra de controlo é a validação mais barata que existe: uma divisão e uma tabela de 23 letras. Mesmo assim, em formulários reais falha mais do que parece, por causa de espaços, hífens, minúsculas, zeros à esquerda e NIE que começam por letra.
Aqui tem o algoritmo oficial, código pronto a copiar em três linguagens e os casos-limite que convém cobrir. E, no fim, um aviso importante: uma letra correta não demonstra que o documento existe.
O algoritmo oficial
O Ministério do Interior espanhol descreve-o assim: divide-se o número por 23 e o resto é substituído por uma letra segundo esta tabela.
| Resto | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Letra | T | R | W | A | G | M | Y | F | P | D | X | B |
| Resto | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Letra | N | J | Z | S | Q | V | H | L | C | K | E |
Escrita de seguida, a tabela é a cadeia TRWAGMYFPDXBNJZSQVHLCKE: a letra é o carácter na posição número % 23.
O exemplo oficial: 12345678 a dividir por 23 dá resto 14, portanto a letra é Z → 12345678Z.
O NIE
Para calcular a letra do NIE, substitui-se a letra inicial por um número e aplica-se o mesmo algoritmo (fonte):
| Letra inicial | Substitui-se por |
|---|---|
| X | 0 |
| Y | 1 |
| Z | 2 |
Exemplos:
X1234567→01234567→ resto 19 → L →X1234567LY1234567→11234567→ resto 10 → X →Y1234567XZ1234567→21234567→ resto 1 → R →Z1234567R
Faça a conta sempre com o número completo de 8 algarismos depois da substituição. Se dividir apenas os 7 algarismos do NIE, o X coincide por acaso (um 0 à esquerda não muda nada), mas Y e Z dão letras erradas.
O código
As três versões fazem o mesmo: normalizam a entrada, verificam o formato (8 algarismos + letra, ou X/Y/Z + 7 algarismos + letra) e comparam a letra.
const LETTERS = "TRWAGMYFPDXBNJZSQVHLCKE";
export function validateNifNie(input) {
const value = String(input).toUpperCase().replace(/[\s.\-]/g, "");
const match = /^([XYZ]\d{7}|\d{8})([A-Z])$/.exec(value);
if (!match) return { valid: false, reason: "format" };
const [, body, letter] = match;
const number = Number(body.replace(/^[XYZ]/, (c) => "XYZ".indexOf(c)));
const expected = LETTERS[number % 23];
return { valid: letter === expected, expected };
}
validateNifNie("12345678Z"); // { valid: true, expected: "Z" }
validateNifNie("x-1234567-l"); // { valid: true, expected: "L" }
validateNifNie("12345678A"); // { valid: false, expected: "Z" }Testámos os três excertos com os exemplos deste artigo.
Casos-limite que aparecem mesmo em formulários
Minúsculas, espaços, pontos e hífens
As pessoas escrevem 12.345.678-z, 12345678 z ou x1234567l. Normalize antes de validar: maiúsculas e sem separadores. Depois, guarde a forma normalizada (12345678Z), não o que o utilizador escreveu.
Zeros à esquerda
Um DNI pode começar por zero. O problema surge quando o valor passa por uma folha de cálculo ou por uma coluna numérica: 01234567L passa a 1234567L e o formato de 8 algarismos falha. A letra não muda (os zeros à esquerda não alteram o resto), por isso pode completar com zeros até 8 algarismos antes de validar:
const padded = value.replace(/^(\d{1,7})([A-Z])$/, (_, n, l) => n.padStart(8, "0") + l);Faça-o apenas se souber que a origem perde zeros; caso contrário, é melhor rejeitar e pedir o número completo.
Letra em falta
Muitos formulários antigos guardam só o número. Pode calcular a letra para a mostrar, mas não a "complete" em silêncio: se o utilizador se enganou num algarismo, estará a fabricar um NIF válido que não é o dele.
Letras que não estão na tabela
A tabela não inclui I, Ñ, O nem U. Se uma delas chegar na posição de controlo, o formato está certo mas a letra nunca coincidirá: a validação devolve false, como esperado.
Outros NIF: CIF e NIF especiais
- O que antes se chamava CIF, hoje NIF das pessoas coletivas e entidades, tem outra estrutura: segundo a Orden EHA/451/2008, uma letra que indica a forma jurídica (A sociedades anónimas, B sociedades por quotas, G associações…), sete algarismos e um carácter de controlo. Esse controlo não se calcula com a tabela do DNI.
- Os estrangeiros sem NIE que precisam de um NIF recebem um que começa por M (Real Decreto 1065/2007, art. 20.º).
O código deste artigo cobre DNI e NIE. Se precisar de validar também CIF e NIF especiais, experimente a nossa ferramenta gratuita, que deteta o tipo automaticamente.
O que a letra não lhe diz
A letra de controlo existe para detetar erros de digitação: um algarismo trocado ou dois algarismos invertidos. Não é um mecanismo de segurança:
- Qualquer pessoa pode calcular a letra de qualquer número. Com um algoritmo público, gerar um NIF "válido" é trivial.
- Uma letra correta não diz que o número existe, que pertence à pessoa do formulário nem que o documento está válido.
Por isso, a letra é um primeiro filtro (útil, barato, imediato no próprio formulário), não uma verificação de identidade.
Como o Constaia o faz
No Constaia, a letra é uma de várias verificações deterministas. Quando analisa um DNI ou um NIE, a resposta inclui a verificação nif_check_digit, a par de outras como mrz_checksums (dígitos de controlo da MRZ) e mrz_matches_visual (a MRZ coincide com os dados impressos). Com checks.holder.document_number confirma ainda que o número lido é o que o utilizador escreveu no formulário.
curl https://api.constaia.com/v1/analyze \
-H "Authorization: Bearer ck_test_..." \
-F file=@nie.jpg \
-F 'options={"expect":["es_dni","es_nie"],"checks":{"not_expired":true,"holder":{"document_number":"X1234567L"}}}'Com uma chave ck_test_… e o ficheiro nie.jpg obtém uma resposta simulada sem gastar créditos (modo de teste). Ainda assim, lembre-se: nem a letra nem a MRZ provam que um documento é autêntico, e o Constaia não é um sistema de KYC biométrico.
Os validadores de NIF/NIE, MRZ e IBAN fazem parte do pacote open source @constaia/validators. Mais detalhes em Checks.
Resumo
- Letra =
TRWAGMYFPDXBNJZSQVHLCKE[número % 23]. - No NIE, substitua X/Y/Z por 0/1/2 antes de dividir.
- Normalize (maiúsculas, sem separadores) e atenção aos zeros à esquerda.
- Uma letra correta só exclui erros de digitação.
Para verificar um número isolado, use o validador gratuito de NIF, NIE e CIF. Para validar documentos completos, crie uma conta gratuita com 250 créditos por mês.
Fontes
- 01Ministério do Interior espanhol — Cálculo do dígito de controlo do NIF/NIE (espanhol)
- 02Dirección General de Ordenación del Juego — Cálculo do dígito de controlo do NIF/NIE
- 03Orden EHA/451/2008 (NIF de pessoas coletivas), BOE (espanhol)
- 04Real Decreto 1065/2007, artigo 20.º (NIF de estrangeiros), BOE (espanhol)