1
1
# pylint: disable=missing-module-docstring
2
2
3
3
import re
4
- from typing import List , Tuple , Dict , Union
5
- from collections import deque
4
+ from typing import List , Dict , Tuple , Union
6
5
7
6
FACTORES_DIGITO_VERIFICADOR : List [int ] = [2 , 3 , 4 , 5 , 6 , 7 ]
8
7
MODULO_DIGITO_VERIFICADOR : int = 11
@@ -18,9 +17,9 @@ class RutBase:
18
17
19
18
def __init__ (self , base : str ):
20
19
self .rut_original : str = base
21
- self .base : str = self ._validar_y_normalizar_base (base )
20
+ self .base : str = self .validar_y_normalizar_base (base )
22
21
23
- def _validar_y_normalizar_base (self , base : str ) -> str :
22
+ def validar_y_normalizar_base (self , base : str ) -> str :
24
23
"""
25
24
Valida y normaliza el número base.
26
25
@@ -53,20 +52,19 @@ class RutDigitoVerificador(RutBase):
53
52
54
53
def __init__ (self , base : str ):
55
54
super ().__init__ (base )
56
- self .digito_verificador : str = self ._calcular_digito_verificador ()
55
+ self .digito_verificador : str = self .calcular_digito_verificador ()
57
56
58
- def _calcular_digito_verificador (self ) -> str :
57
+ def calcular_digito_verificador (self ) -> str :
59
58
"""
60
59
Calcula el dígito verificador del RUT.
61
60
62
61
Returns:
63
62
str: El dígito verificador del RUT.
64
63
"""
65
- factores = deque (FACTORES_DIGITO_VERIFICADOR )
66
64
suma_parcial : int = sum (
67
- int (digito ) * factores [0 ] for digito in reversed (str (self .base ))
65
+ int (digito ) * FACTORES_DIGITO_VERIFICADOR [i % 6 ]
66
+ for i , digito in enumerate (reversed (str (self .base )))
68
67
)
69
- factores .rotate (- 1 )
70
68
digito_verificador : int = (
71
69
MODULO_DIGITO_VERIFICADOR - suma_parcial % MODULO_DIGITO_VERIFICADOR
72
70
) % MODULO_DIGITO_VERIFICADOR
@@ -76,24 +74,6 @@ def __str__(self) -> str:
76
74
return self .digito_verificador
77
75
78
76
79
- class RutValidador :
80
- """Valida un RUT chileno."""
81
-
82
- @staticmethod
83
- def validar_formato (rut : str ) -> Tuple [bool , str ]:
84
- """Valida el formato del RUT."""
85
- match = re .fullmatch (RUT_REGEX , rut )
86
- if not match :
87
- return False , f"El formato del RUT '{ rut } ' es inválido."
88
- return True , match .group (1 )
89
-
90
- @staticmethod
91
- def validar_digito_verificador (base : str , digito : str ) -> bool :
92
- """Valida el dígito verificador del RUT."""
93
- digito_calculado = RutDigitoVerificador (base ).digito_verificador
94
- return digito .lower () == digito_calculado
95
-
96
-
97
77
class Rut :
98
78
"""
99
79
Representa un RUT chileno.
@@ -108,26 +88,37 @@ class Rut:
108
88
formatear_lista_ruts: Formatea una lista de RUTs según las opciones especificadas.
109
89
"""
110
90
91
+ PATRON_RUT = re .compile (RUT_REGEX )
92
+
111
93
def __init__ (self , rut : str ):
112
94
self .rut_string : str = str (rut ).strip ()
113
- self ._validar_rut ()
95
+ self ._validar_formato_rut ()
96
+ self ._validar_digito_verificador ()
114
97
self .base = RutBase (self .base_string )
115
98
self .digito_verificador = RutDigitoVerificador (self .base_string )
116
99
117
- def _validar_rut (self ) -> None :
118
- """Valida el formato y el dígito verificador del RUT."""
119
- es_valido , resultado = RutValidador .validar_formato (self .rut_string )
120
- if not es_valido :
121
- raise RutInvalidoError (resultado )
122
-
123
- self .base_string = resultado
124
- match = re .fullmatch (RUT_REGEX , self .rut_string )
100
+ def _validar_formato_rut (self ) -> None :
101
+ match = Rut .PATRON_RUT .fullmatch (self .rut_string )
102
+ if not match :
103
+ raise RutInvalidoError (
104
+ f"El formato del RUT '{ self .rut_string } ' es inválido."
105
+ )
106
+ self .base_string : str = match .group (1 )
107
+
108
+ def _validar_digito_verificador (self ) -> None :
109
+ match = Rut .PATRON_RUT .fullmatch (self .rut_string )
125
110
digito_verificador_input = match .group (3 ).lower () if match .group (3 ) else None
126
-
127
- if digito_verificador_input and not RutValidador .validar_digito_verificador (self .base_string , digito_verificador_input ):
111
+ digito_verificador_calculado = RutDigitoVerificador (
112
+ self .base_string
113
+ ).digito_verificador
114
+
115
+ if (
116
+ digito_verificador_input
117
+ and digito_verificador_input != digito_verificador_calculado
118
+ ):
128
119
raise RutInvalidoError (
129
120
f"El dígito verificador '{ digito_verificador_input } ' no coincide con "
130
- f"el dígito verificador calculado '{ self . digito_verificador } '."
121
+ f"el dígito verificador calculado '{ digito_verificador_calculado } '."
131
122
)
132
123
133
124
def __str__ (self ) -> str :
@@ -152,7 +143,10 @@ def formatear(self, separador_miles: bool = False, mayusculas: bool = False) ->
152
143
+ rut .split ("-" )[1 ]
153
144
)
154
145
155
- return rut .upper () if mayusculas else rut
146
+ if mayusculas :
147
+ rut = rut .upper ()
148
+
149
+ return rut
156
150
157
151
@staticmethod
158
152
def _agregar_separador_miles (numero : str ) -> str :
@@ -172,22 +166,28 @@ def _validar_lista_ruts(ruts: List[str]) -> Dict[str, List[Union[str, Tuple[str,
172
166
173
167
@staticmethod
174
168
def _formatear_csv (ruts_formateados : List [str ]) -> str :
175
- return f"rut\n { chr (10 ).join (ruts_formateados )} "
169
+ cadena_ruts : str = "\n " .join (ruts_formateados )
170
+ return f"rut\n { cadena_ruts } "
176
171
177
172
@staticmethod
178
173
def _formatear_xml (ruts_formateados : List [str ]) -> str :
179
- return "\n " .join (["<root>" ] + [f" <rut>{ rut } </rut>" for rut in ruts_formateados ] + ["</root>" ])
174
+ xml_lines : List [str ] = ["<root>" ]
175
+ for rut in ruts_formateados :
176
+ xml_lines .append (f" <rut>{ rut } </rut>" )
177
+ xml_lines .append ("</root>" )
178
+ return "\n " .join (xml_lines )
180
179
181
180
@staticmethod
182
181
def _formatear_json (ruts_formateados : List [str ]) -> str :
183
- return str ([{"rut" : rut } for rut in ruts_formateados ])
182
+ ruts_json : List [Dict [str , str ]] = [{"rut" : rut } for rut in ruts_formateados ]
183
+ return str (ruts_json )
184
184
185
185
@staticmethod
186
186
def formatear_lista_ruts (
187
187
ruts : List [str ],
188
188
separador_miles : bool = False ,
189
189
mayusculas : bool = False ,
190
- formato : Union [ str , None ] = None ,
190
+ formato = None ,
191
191
) -> str :
192
192
"""
193
193
Formatea una lista de RUTs según las opciones especificadas.
@@ -207,23 +207,25 @@ def formatear_lista_ruts(
207
207
"xml" : Rut ._formatear_xml ,
208
208
"json" : Rut ._formatear_json ,
209
209
}
210
- ruts_validos_invalidos : Dict [str , List [Union [ str , Tuple [ str , str ]] ]] = Rut ._validar_lista_ruts (ruts )
210
+ ruts_validos_invalidos : Dict [str , List [str ]] = Rut ._validar_lista_ruts (ruts )
211
211
ruts_validos : List [str ] = ruts_validos_invalidos ["validos" ]
212
212
ruts_invalidos : List [Tuple [str , str ]] = ruts_validos_invalidos ["invalidos" ]
213
213
214
- resultado : List [ str ] = []
214
+ resultado : str = ""
215
215
if ruts_validos :
216
216
ruts_validos_formateados : List [str ] = [
217
217
Rut (rut ).formatear (separador_miles , mayusculas ) for rut in ruts_validos
218
218
]
219
- resultado . append ( "RUTs válidos:" )
220
- if formato in formato_salida :
221
- resultado . append ( formato_salida [formato ](ruts_validos_formateados ) )
219
+ resultado += "RUTs válidos:\n "
220
+ if formato in ( "csv" , "xml" , "json" ) :
221
+ resultado += formato_salida [formato ](ruts_validos_formateados )
222
222
else :
223
- resultado .extend (ruts_validos_formateados )
223
+ resultado += "\n " .join (ruts_validos_formateados )
224
+ resultado += "\n \n "
224
225
225
226
if ruts_invalidos :
226
- resultado .append ("\n RUTs inválidos:" )
227
- resultado .extend (f"{ rut } - { error } " for rut , error in ruts_invalidos )
227
+ resultado += "RUTs inválidos:\n "
228
+ for rut , error in ruts_invalidos :
229
+ resultado += f"{ rut } - { error } \n "
228
230
229
- return " \n " . join ( resultado )
231
+ return resultado
0 commit comments