Validación de NIFs y CIFs en Python 3

written by uve 24 February 2012

Hace más de un año escribí un par de entradas acerca de cómo realizar la validación de NIFs y CIFs en Python. He adaptado ese código para Python 3k y modificado un par de detalles.

import re
from functools import reduce


DNI = re.compile('(?P<dni>\d{8})(?P<letra>[A-Z])')
DNI_HYPHEN = re.compile('(?P<dni>\d{8})-(?P<letra>[A-Z])')
CIF = re.compile('(?P<letra>[A-H]|[J-N]|[P-S]|[UVW])(?P<numeracion>\d{7})(?P<control>[0-9A-J])')
CIF_HYPHEN = re.compile('(?P<letra>[A-H]|[J-N]|[P-S]|[UVW])-(?P<numeracion>\d{7})(?P<control>[0-9A-J])')


def validate_nif(value):
    value = str(value).upper()
    match = DNI.match(value)
    if match is None:
        match = DNI_HYPHEN.match(value)
    if match is None:
        raise Exception

    dni = int(match.group('dni'))
    letra = match.group('letra')

    LETRAS_NIF = 'TRWAGMYFPDXBNJZSQVHLCKE'
    if LETRAS_NIF[dni%23] != letra:
        raise Exception
    return '%s%s' % (dni, letra)


def validate_cif(value):
    value = str(value).upper()
    match = CIF.match(value)
    if match is None:
        match = CIF_HYPHEN.match(value)
    if match is None:
        raise Exception

    LETRAS_CIF = 'ABCDEFGHJKLMNPQRSUVW' # Letras de CIF válidas
    DC_NUMERICO_CIF = 'ABEH' # CIFs con número como dígito de control
    DC_LETRA_CIF = 'KPQS' # CIFs con letra como dígito de control
    ALPHA_CIF = 'JABCDEFGHI' # Correspondencia entre letra y dígito de control

    # No todas las letras son válidas
    if letra not in LETRAS_CIF:
        raise Exception

    # Obtenemos la información
    letra = match.group('letra')
    numeracion = match.group('numeracion')
    control = match.group('control')

    # Suma de los pares
    a = reduce(lambda x, y: int(x)+int(y), numeracion[1::2])
    # Suma de la suma de los dígitos de los impares * 2
    b = sum(
        [
            int(reduce(lambda x,y: int(x)+int(y), impar))
            for impar in map(lambda x: str(int(x)*2), numeracion[::2])
        ]
    )
    c = a + b
    e = c % 10
    d = (10-e) % 10

    if letra in DC_NUMERICO_CIF:
        d = str(d) # Es numérico
    elif letra in DC_LETRA_CIF:
        d = ALPHA_CIF[d] # Es una letra
    else:
        # Puede ser tanto letra como número
        if control.isalpha():
            d = ALPHA_CIF[d]
        else:
            d = str(d)
    if d != control:
        raise Exception
    return '%s%s%s' % (letra, numeracion, control)

Tags

La teoría es cuando crees saber algo, pero no funciona.
La práctica es cuando algo funciona, pero no sabes por qué.
Los programadores combinan la teoría y la práctica:
Nada funciona y no saben por qué.