DNI
Documento Nacional de Identidad (DNI)¶
Overview¶
The Spanish DNI is the standard identification number for Spanish citizens. It is eight digits plus a control letter. The letter guards against typos by encoding the remainder of the numeric part modulo 23.
Algorithm Walkthrough¶
- Canonicalise the input by uppercasing it; values must already be the correct length and contain no separators.
- Format check that the result matches
\d{8}[A-Z]. - Compute the remainder of the eight-digit number divided by 23.
- Map the remainder to the fixed sequence
TRWAGMYFPDXBNJZSQVHLCKE. - Compare the expected letter with the provided one. A mismatch means the identifier is invalid.
Worked Examples¶
12345678Z:12345678 % 23 == 14, and the sequence at position 14 isZ.00000000T: the remainder is 0, yielding the first letterT.12345678A: remainder 14 →Z, so the providedAis rejected.
Formal Specification¶
- Input must be exactly 9 ASCII characters.
- Characters 1–8: digits
0-9. - Character 9: uppercase letter
A-Z. - Let
nbe the integer formed by the first eight digits. - Let
letters = "TRWAGMYFPDXBNJZSQVHLCKE". - Valid if and only if
letters[n % 23] == character9.
Using the Library¶
from spanish_nif import DNI, InvalidDNI
dni = DNI("12345678Z")
assert dni.digits == "12345678"
assert dni.letter == "Z"
try:
DNI("12345678A")
except InvalidDNI as error:
print(error)
Generating Sample DNIs¶
Use DNI.random() when you need valid placeholders for fixtures or demos:
from spanish_nif import DNI
dni = DNI.random()
assert len(dni) == 9
assert dni.isupper()
Pass a random.Random instance only when you need reproducible sequences.
Official References¶
- Real Decreto 1553/2005, de 23 de diciembre, por el que se regula la expedición del Documento Nacional de Identidad — el artículo 11 fija que el DNI incorpora el número del NIF como ocho dígitos más la letra de control.