Código fuente para mexa.CurpUtils

# encoding: utf-8
"""
Módulo que contiene un conjunto de utilerías diseñadas
para darle soporte a la Clase: CurpField
"""
import re
import math
import datetime
import string
from random import randint, choice
from calendar import monthrange
from mexa.Estados import estados

ALPHABET = string.ascii_uppercase
DIGITS = string.digits
VOWELS = "AEIOU"
CONSONANTS = [letter for letter in ALPHABET if letter not in VOWELS]

[documentos]class Rand(): """Devuelve aleatoriamente diferentes elementos"""
[documentos] @staticmethod def digito(): """Regresa un valor aleatorio entre 0 a 9 :returns: i ∈ (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) :rtype: int Example: >>> Rand.digito() # 3 (por ejemplo) """ return str(randint(0, 9))
[documentos] @staticmethod def vocal(): """Regresa una vocal aleatoriamente :returns: s ∈ (A, E, I, O , U) :rtype: str Example: >>> Rand.digito() # 3 (por ejemplo) """ return choice(VOWELS)
[documentos] @staticmethod def consonante(): """Devuelve una consonante de manera aleatoria. :returns: s ∈ ALPHABET) ^ (s ∉ VOWELS) :rtype: str Example: >>> Rand.consonante() # M (por ejemplo) """ return choice(CONSONANTS)
[documentos] @staticmethod def sexo(): """Devuelve el sexo en modo aleatorio :returns: s ∈ (H, M) :rtype: str Example: >>> Rand.sexo() # M (por ejemplo) """ return choice(['H', 'M'])
[documentos] @staticmethod def estado(): """Devuelve el código de un estado de forma aleatoria :returns: s ∈ ESTADOS_CODIGOS :rtype: str Example: >>> Rand.estado() # "MN" ("Michoacán de Ocampo",por ejemplo) """ return choice(list(estados.keys()))
[documentos] @staticmethod def fecha() -> str: """Devuelve una fecha aleatoria en formato de 6 carácteres. :returns: AAMMDD :rtype: str Example: >>> Rand.fecha() # "200229" ("29/feb/2020", por ejemplo) """ y_actual = datetime.date.today().year y = randint(y_actual - 80, y_actual - 10) m = randint(1, 12) dias_info = monthrange(y, m) d = randint(1, dias_info[1]) return str(y)[2:4] + str(m).rjust(2, '0') + str(d).rjust(2, '0')
[documentos]class CurpTools(): """Clase que modela el CURP"""
[documentos] @staticmethod def sanitizar(value:str) -> str: """Recibe un string y devuelve su equivalente normalizado. :param value: valor del str a sanitizar. :type value: str :param value:str: :returns: el str sanitizado. :rtype: str """ remplazos = { 'A': ['Ã', 'À', 'Á', 'Ä', 'Â', 'ã', 'à', 'á', 'ä', 'â'], 'E': ['È', 'É', 'Ë', 'Ê', 'è', 'é', 'ë', 'ê'], 'I': ['Ì', 'Í', 'Ï', 'Î', 'ì', 'í', 'ï', 'î'], 'O': ['Ò', 'Ó', 'Ö', 'Ô', 'ò', 'ó', 'ö', 'ô'], 'U': ['Ù', 'Ú', 'Ü', 'Û', 'ù', 'ú', 'ü', 'û'], 'C': ['Ç', 'ç'], 'X': ['ñ', 'Ñ'], } out = '' keys = remplazos.keys() for char in value: insertado = False for key in keys: if char in remplazos[key]: insertado = True out += key break if not insertado: out += char return out.upper()
[documentos] @staticmethod def primer_vocal_interna(palabra:str) -> str: """Devuelve la primer vocal de parabra :param palabra: La palabra sobre en cual se buscará la primer vocal. :type palabra: str :param palabra:str: :returns: La primer vocal interna encontrada, Si no encuentra devuelve X :rtype: str Example: >>> CurpTools.primer_vocal_interna('OLLA') # A >>> CurpTools.primer_vocal_interna('ELY') # X (no encontró) """ if len(palabra) == 0: return 'X' for c in palabra[1:]: if c in ('A','E','I','O','U'): return c return 'X'
[documentos] @staticmethod def primer_consonante_interna(palabra): """Devuelve el valor de la primer consonante interna en palabra :param palabra: palabra con la que se van a trabajar. :type palabra: str :returns: El valor de la primer consonante. :rtype: str Example: >>> CurpTools.primer_consonante_interna('JOEL') # L >>> CurpTools.primer_consonante_interna('TIO') # X (No se encontró) """ if len(palabra) == 0: return 'X' for c in palabra[1:]: if c not in ('A','E','I','O','U'): return c return 'X'
[documentos] @staticmethod def primer_letra(palabra: str) -> str: """Devuelve la primer letra de la palabra recibida. :param palabra: La parabra en la que se extrae el primer caracter. :type palabra: str :param palabra: str: :returns: la primer letra en caso que la cadena es vacia regresa X :rtype: str Example: >>> CurpTools.primer_letra('JOEL') # J >>> CurpTools.primer_letra('Miguel') # M """ return palabra[0] if len(palabra) else 'X'
# # # a la hora de calcular el CURP.
[documentos] @staticmethod def quitar_conjunciones(s): """Cuando el nombre o los apellidos son compuestos y tienen proposiciones, contracciones o conjunciones, se deben eliminar esas palabras son eliminadas. :param s: string el cual se le quitaran las conjunciones. :type s: str :returns: El texto de entrada sin contracciones, conjunciones, etc.. :rtype: str Example: >>> CurpTools.quitar_conjunciones("DE LA CRUZ") # "CRUZ" >>> CurpTools.quitar_conjunciones("DEL CUELLO DI ANGEL") # "CUELLO ANGEL" """ parts = CurpTools.sanitizar(s).split(' ') if len(parts) == 1: return parts[0] compuestos = ( 'DA', 'DAS', 'DE', 'DEL', 'DER', 'DI', 'DIE', 'DD', 'EL', 'LA', 'LOS', 'LAS', 'LE', 'LES', 'MAC', 'MC', 'VAN', 'VON', 'Y' ) out = ' '.join([e for e in parts if e not in compuestos]) return s if out == '' else out
[documentos] @staticmethod def limpiar_mal_palabra(palabra:str) -> str: """Transforma una "mala palabra". :param palabra: Palabra a buscar si es "mala palabra". :type palabra: str :param palabra:str: :returns: la palabra original en caso de ser "mala" la limpia. :rtype: str Example: >>> CurpTools.limpiar_mal_palabra("CACA") # "CXCA" >>> CurpTools.limpiar_mal_palabra("HOLA") # "HOLA" (sin cambio) >>> CurpTools.limpiar_mal_palabra("PITO") # "PXTO" """ malasPalabras = [ 'BACA', 'BAKA', 'BUEI', 'BUEY', 'CACA', 'CACO', 'CAGA', 'CAGO', 'CAKA', 'CAKO', 'COGE', 'COGI', 'COJA', 'COJE', 'COJI', 'COJO', 'COLA', 'CULO', 'FALO', 'FETO', 'GETA', 'GUEI', 'GUEY', 'JETA', 'JOTO', 'KACA', 'KACO', 'KAGA', 'KAGO', 'KAKA', 'KAKO', 'KOGE', 'KOGI', 'KOJA', 'KOJE', 'KOJI', 'KOJO', 'KOLA', 'KULO', 'LILO', 'LOCA', 'LOCO', 'LOKA', 'LOKO', 'MAME', 'MAMO', 'MEAR', 'MEAS', 'MEON', 'MIAR', 'MION', 'MOCO', 'MOKO', 'MULA', 'MULO', 'NACA', 'NACO', 'PEDA', 'PEDO', 'PENE', 'PIPI', 'PITO', 'POPO', 'PUTA', 'PUTO', 'QULO', 'RATA', 'ROBA', 'ROBE', 'ROBO', 'RUIN', 'SENO', 'TETA', 'VACA', 'VAGA', 'VAGO', 'VAKA', 'VUEI', 'VUEY', 'WUEI', 'WUEY' ] if palabra not in malasPalabras: return palabra return f'{palabra[0]}X{palabra[2:4]}'
[documentos] @staticmethod def nombre_de_pila(nombre:str) -> str: """Devuelve el nombre de pila, en donde si el primer nombre es María o José devolverá el segundo nombre. :param nombre: Nombre del que se sacará el nombre de pila :type nombre: str :param nombre:str: :returns: Nombre de pila :rtype: str Example: >>> CurpTools.nombre_de_pila("JOSE ANGEL") # "ANGEL" >>> CurpTools.nombre_de_pila("MA. FERNANDA") # "FERNANDA" >>> CurpTools.nombre_de_pila("JUAN ANGEL") # "JUAN" >>> CurpTools.nombre_de_pila("J. DEL CIELO") # "CIELO" """ parts = CurpTools.quitar_conjunciones(nombre).split(' ') if len(parts) <= 1: return parts[0] especiales = ('JOSE', 'J.', 'MARIA', 'MA.') for p in parts: if p not in especiales: return p return parts[0] if len(parts) else 'X'
[documentos] @staticmethod def anio(last2_digits:str, homo_serial:str) -> int: """Devuelve al año, agregando los primeros digitos, esto si la parte de la homoclave que genera la serialización para evitar curps repetidos Si es mayor a A entonces nacio despues del año 2000 :param last2_digits: Los dos ultimos digitos del año. :type last2_digits: str :param homo_serial: Valor de la homoclave :type homo_serial: str :param last2_digits:str: :param homo_serial:str: :returns: El año obtenido. :rtype: int Example: >>> CurpTools.anio("20", "0") # 1920 >>> CurpTools.anio("20", "A") # 2020 """ y = int(last2_digits) if math.isnan(y): return None centenas = 19 if homo_serial in "01234566789" else 20 return (centenas * 100) + y
[documentos] @staticmethod def fecha_to_6digits(fecha) -> str: """Recibe una fecha y la normaliza a formato AAMMDD :param fecha: La fecha :returns: La fecha en formato AAMMDD :rtype: str """ if isinstance(fecha, datetime.date): fecha = fecha.strftime("%Y-%m-%d") if not isinstance(fecha, str): return None if re.match(r'^\d{6}$', fecha): return fecha if not re.match(r'^\d{4}-\d{2}-\d{2}$', fecha): return None return f'{fecha[2:4]}{fecha[5:7]}{fecha[8:10]}'
[documentos] @staticmethod def estado_to_2chars(edo): """Recibe el estado devuelve el código del mismo a dos caracteres :param edo: El nombre del estado :type edo: str :returns: El codigo del estado :rtype: str """ if len(edo) != 2: try: index = list(estados.values()).index(edo) edo = list(estados.keys())[index] # Prints george except ValueError: return None return edo