From 8a8f42236b80b86728a4acea9e53595dfc4e7c74 Mon Sep 17 00:00:00 2001 From: Juan Mosquera Date: Mon, 2 Jun 2025 16:06:21 -0500 Subject: [PATCH 1/6] =?UTF-8?q?Clases=20Base=20para=20analisis=20l=C3=A9xi?= =?UTF-8?q?co=20de=20expresiones=20regulares?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/logic.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/logic.py b/src/logic.py index e69de29..814fee4 100644 --- a/src/logic.py +++ b/src/logic.py @@ -0,0 +1,3 @@ +print("hola mnundo" \ +"hola mundo") +print("hola mundo") \ No newline at end of file From 88f81f9af2767bb3c1cc2a8fbf6700051f1bbda1 Mon Sep 17 00:00:00 2001 From: Juan Mosquera Date: Mon, 2 Jun 2025 16:09:21 -0500 Subject: [PATCH 2/6] =?UTF-8?q?base=20de=20clases=20para=20analisis=20l?= =?UTF-8?q?=C3=A9xico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/logic.py | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/src/logic.py b/src/logic.py index 814fee4..207f002 100644 --- a/src/logic.py +++ b/src/logic.py @@ -1,3 +1,95 @@ -print("hola mnundo" \ -"hola mundo") -print("hola mundo") \ No newline at end of file +import re +#El interprete de las expresiones brindadas +class logic: + + def _init_(self,texto): + self.texto=texto + self.division="" + self.constantes=[] + self.funciones=[] + self.referencias=[] + self.value= False; + + def funcionesFun(self): + #Clasificacion de las funciones presentes, solo despues del igual + try: + #parte de interes, despues de = + formula=self.division[1] + + #buscar las funciones con re + #pattern de las funciones es con mayuscula + pattern = r"\b([A-Z]+)\s*\(" + #busca todas las funciones por el pattern que contiene + + self.funciones= re.findall(pattern,formula) + except IndexError: + print("no se ecnontro ninguna funcion asignada") + + except Exception as e: + print(f"Ocurrio un error en el proceso de clasificacion {e}") + + def constantesFun(self): + #clasificacion de constantes + try: + #las cosntantes solo se encuentran despues del igual + formula= self.division[1] + #patern de las constantes + pattern = r'[-+]?\b\d+(?:\.\d+)?\b' + self.constantes = re.findall(pattern, formula) + except IndexError: + print("No se encontro ninguna constante") + except Exception as e: + print(f"Ocurrio un error de ejecucion {e}") + + def referenciasFun(self): + #Clasificacion de referencias + try: + #Clasificacion mediante el pattern + formula= self.division[1] + pattern = r'\b[A-Z]{1,3}[1-9][0-9]{0,4}\b' + self.referencias = re.findall(pattern, formula) + except IndexError: + print("No se encontro ninguna constante") + except Exception as e: + print(f"Ocurrio un error de ejecucion {e}") + + + + def imprimirCadenaFun(self): + if self.value==True: + #Mostrar las dos partes del igual al usuario + print(f"la cadena esta dividiad en {self.division}, funciones {self.funciones}, constantes {self.constantes},referencias{self.referencias}") + else: + #cuando no se cumpe la expresion repetir el proceso + print("No pudes imprimr nada el valor ingreado no corresponde a una exprecion logica ") + + + def clasificacionFun(self): + #Verifcar si hay una expresion de igualdad + for i in self.texto: + if i=="=": + self.value=True + #recorrre la cadena en busca de una expresion valida + #clasificacion de la primera igualdad + try: + if self.value==True: + self.division=self.texto.split(sep="=",maxsplit=2) + except: + print("No se encuentra ninguna expresion de igualdad, intentelo de nuevo") + return + self.funcionesFun() + self.constantesFun() + self.referenciasFun() + self.imprimirCadenaFun() + + + + + +#parte para hacer el test de la prueba logica +while True: + test = input("Ingrea tu expresion a valorar: ") + prueba = logic(test) + prueba.clasificacionFun() + if(prueba.value==True): + break \ No newline at end of file From de8f8cf3c3a6132c257f672d0a60a2baa64015e0 Mon Sep 17 00:00:00 2001 From: felipeabril520 Date: Wed, 4 Jun 2025 08:53:45 -0500 Subject: [PATCH 3/6] feat: corregido constructor y funciones de parsing --- src/logic.py | 126 ++++++++++++++++++++++----------------------------- 1 file changed, 55 insertions(+), 71 deletions(-) diff --git a/src/logic.py b/src/logic.py index 207f002..4b89215 100644 --- a/src/logic.py +++ b/src/logic.py @@ -1,95 +1,79 @@ import re -#El interprete de las expresiones brindadas -class logic: - def _init_(self,texto): - self.texto=texto - self.division="" - self.constantes=[] - self.funciones=[] - self.referencias=[] - self.value= False; - +# El interprete de las expresiones brindadas +class Logic: + def __init__(self, texto): + self.texto = texto.strip() + self.division = "" + self.constantes = [] + self.funciones = [] + self.referencias = [] + self.rangos = [] + self.value = False + def funcionesFun(self): - #Clasificacion de las funciones presentes, solo despues del igual try: - #parte de interes, despues de = - formula=self.division[1] - - #buscar las funciones con re - #pattern de las funciones es con mayuscula + formula = self.division[1].upper() # Normalizar a mayúsculas pattern = r"\b([A-Z]+)\s*\(" - #busca todas las funciones por el pattern que contiene - - self.funciones= re.findall(pattern,formula) + self.funciones = re.findall(pattern, formula) except IndexError: - print("no se ecnontro ninguna funcion asignada") - + print("No se encontró ninguna función") except Exception as e: - print(f"Ocurrio un error en el proceso de clasificacion {e}") - + print(f"Error en funciones: {e}") + def constantesFun(self): - #clasificacion de constantes - try: - #las cosntantes solo se encuentran despues del igual - formula= self.division[1] - #patern de las constantes + try: + formula = self.division[1] pattern = r'[-+]?\b\d+(?:\.\d+)?\b' self.constantes = re.findall(pattern, formula) except IndexError: - print("No se encontro ninguna constante") - except Exception as e: - print(f"Ocurrio un error de ejecucion {e}") + print("No se encontró ninguna constante") + except Exception as e: + print(f"Error en constantes: {e}") def referenciasFun(self): - #Clasificacion de referencias try: - #Clasificacion mediante el pattern - formula= self.division[1] - pattern = r'\b[A-Z]{1,3}[1-9][0-9]{0,4}\b' - self.referencias = re.findall(pattern, formula) - except IndexError: - print("No se encontro ninguna constante") - except Exception as e: - print(f"Ocurrio un error de ejecucion {e}") - + formula = self.division[1].upper() + # Detectar rangos como A1:B34 + self.rangos = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}:[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) + # Detectar referencias simples (excluyendo las que ya están en rangos) + todas = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) + partes_de_rangos = [celda for r in self.rangos for celda in r.split(":")] + self.referencias = [ref for ref in todas if ref not in partes_de_rangos] + except Exception as e: + print(f"Error en referencias: {e}") - def imprimirCadenaFun(self): - if self.value==True: - #Mostrar las dos partes del igual al usuario - print(f"la cadena esta dividiad en {self.division}, funciones {self.funciones}, constantes {self.constantes},referencias{self.referencias}") + if self.value: + print("\n--- Resultado ---") + print(f"Funciones encontradas: {self.funciones}") + print(f"Constantes encontradas: {self.constantes}") + print(f"Referencias individuales: {self.referencias}") + print(f"Rangos detectados: {self.rangos}") + print("------------------\n") else: - #cuando no se cumpe la expresion repetir el proceso - print("No pudes imprimr nada el valor ingreado no corresponde a una exprecion logica ") - + print("No puedes imprimir nada. La fórmula no empieza con '='.") def clasificacionFun(self): - #Verifcar si hay una expresion de igualdad - for i in self.texto: - if i=="=": - self.value=True - #recorrre la cadena en busca de una expresion valida - #clasificacion de la primera igualdad - try: - if self.value==True: - self.division=self.texto.split(sep="=",maxsplit=2) - except: - print("No se encuentra ninguna expresion de igualdad, intentelo de nuevo") + if "=" in self.texto: + self.value = True + else: + print("❌ La fórmula no contiene '='.") return - self.funcionesFun() - self.constantesFun() - self.referenciasFun() - self.imprimirCadenaFun() - - - + try: + self.division = self.texto.split("=", maxsplit=1) + self.funcionesFun() + self.constantesFun() + self.referenciasFun() + self.imprimirCadenaFun() + except Exception as e: + print(f"Ocurrió un error general: {e}") -#parte para hacer el test de la prueba logica +# Parte para hacer el test while True: - test = input("Ingrea tu expresion a valorar: ") - prueba = logic(test) + test = input("Ingrese su expresión a valorar (ej: =SUMA(1,A1,B2:B5)): ") + prueba = Logic(test) prueba.clasificacionFun() - if(prueba.value==True): - break \ No newline at end of file + if prueba.value: + break From 0aa0823562b8637b607a5a2e44df33aaba182da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Avila=20G=C3=B3mez?= <72152529+SantiagoAvila21@users.noreply.github.com> Date: Wed, 4 Jun 2025 21:48:24 -0500 Subject: [PATCH 4/6] Doc: README.md logic.py --- src/README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/README.md diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..a9232a8 --- /dev/null +++ b/src/README.md @@ -0,0 +1,42 @@ +# 🧮 Archivo: `logic.py` + +Este archivo implementa una clase llamada `Logic` en Python, la cual sirve como un **intérprete básico de expresiones tipo Excel**. Su propósito es descomponer una fórmula dada en sus partes fundamentales: funciones, constantes, referencias a celdas y rangos. + +--- + +## ✨ Funcionalidad del archivo + +Al ejecutar el script, el usuario puede ingresar una fórmula por consola (por ejemplo: `=SUMA(1,A1,B2:B5)`), y el programa identificará automáticamente: + +- Funciones utilizadas (`SUMA`) +- Números constantes (`1`) +- Referencias a celdas individuales (`A1`) +- Rangos de celdas (`B2:B5`) + +--- + +## 📌 Estructura del código + +El archivo contiene: + +### Clase: `Logic` + +| Método | Función | +|---------------------|-------------------------------------------------------------------------| +| `__init__` | Inicializa la expresión y prepara los contenedores | +| `funcionesFun()` | Extrae los nombres de funciones usando expresiones regulares | +| `constantesFun()` | Detecta constantes numéricas en la expresión | +| `referenciasFun()` | Identifica celdas individuales y rangos, evitando duplicación | +| `imprimirCadenaFun()`| Muestra los resultados si la fórmula es válida | +| `clasificacionFun()` | Ejecuta el análisis completo si la cadena inicia con `=` | + +### Interfaz por consola + +Un bucle `while` al final del archivo permite al usuario probar expresiones hasta ingresar una válida (que comience con `=`). + +--- + +## ▶️ Cómo ejecutar + +```bash +python logic_interpreter.py From 173df7b2f3ea923c57b0adae77995db0ac22bb27 Mon Sep 17 00:00:00 2001 From: Juan Mosquera Date: Wed, 11 Jun 2025 19:23:22 -0500 Subject: [PATCH 5/6] docs: docstrings de la primera funcionalidad --- src/logic.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/logic.py b/src/logic.py index 4b89215..e3e3741 100644 --- a/src/logic.py +++ b/src/logic.py @@ -54,6 +54,31 @@ def imprimirCadenaFun(self): else: print("No puedes imprimir nada. La fórmula no empieza con '='.") + def direccionamientoFun(self): + funciones_basicas = {"SUMA", "MAX", "MIN", "PROMEDIO"} + funciones_ext = {"SI", "CONTAR.SI", "CONCATENAR"} + + print("\n--- Clasificación y Direccionamiento ---") + for constante in self.constantes: + print(f"🔹 Constante '{constante}' → Evaluación directa") + + for referencia in self.referencias: + print(f"🔹 Referencia '{referencia}' → Resolución de referencia") + + for rango in self.rangos: + print(f"🔹 Rango '{rango}' → Resolución de referencia (rango)") + + for funcion in self.funciones: + if funcion in funciones_basicas: + print(f"🔹 Función básica '{funcion}' → Evaluación funcional") + elif funcion in funciones_ext: + print(f"🔹 Función extendida '{funcion}' → Evaluación funcional") + else: + print(f"❌ Función '{funcion}' no reconocida → Error: función desconocida") + + print("-----------------------------------------\n") + + def clasificacionFun(self): if "=" in self.texto: self.value = True @@ -67,10 +92,15 @@ def clasificacionFun(self): self.constantesFun() self.referenciasFun() self.imprimirCadenaFun() + self.direccionamientoFun() except Exception as e: print(f"Ocurrió un error general: {e}") -# Parte para hacer el test + + + + +#parte para hacer el test de la prueba logica while True: test = input("Ingrese su expresión a valorar (ej: =SUMA(1,A1,B2:B5)): ") prueba = Logic(test) From 9b06044696dfb3d5559ce79774cab3c4a4e957a8 Mon Sep 17 00:00:00 2001 From: Juan Mosquera Date: Tue, 17 Jun 2025 22:27:51 -0500 Subject: [PATCH 6/6] feat doc test: docstrings pytest y errores --- src/logic.py | 168 ++++++++++++++++++++++----------------------- test/test_logic.py | 29 ++++++++ 2 files changed, 113 insertions(+), 84 deletions(-) create mode 100644 test/test_logic.py diff --git a/src/logic.py b/src/logic.py index e3e3741..cf203e8 100644 --- a/src/logic.py +++ b/src/logic.py @@ -1,8 +1,21 @@ import re -# El interprete de las expresiones brindadas class Logic: + """ + Clase Logic para interpretar y clasificar elementos léxicos en una fórmula de Excel. + + Atributos: + texto (str): La fórmula o expresión a analizar. + division (list): Texto dividido por el símbolo '='. + constantes (list): Lista de constantes numéricas. + funciones (list): Lista de funciones detectadas. + referencias (list): Lista de referencias individuales. + rangos (list): Lista de rangos de celdas. + value (bool): Indica si la fórmula es válida (empieza con '='). + """ + def __init__(self, texto): + """Inicializa una instancia con la fórmula dada.""" self.texto = texto.strip() self.division = "" self.constantes = [] @@ -12,98 +25,85 @@ def __init__(self, texto): self.value = False def funcionesFun(self): - try: - formula = self.division[1].upper() # Normalizar a mayúsculas - pattern = r"\b([A-Z]+)\s*\(" - self.funciones = re.findall(pattern, formula) - except IndexError: - print("No se encontró ninguna función") - except Exception as e: - print(f"Error en funciones: {e}") + """Detecta y registra funciones en la fórmula.""" + formula = self.division[1].upper() + pattern = r"\b([A-Z]+)\s*\(" + self.funciones = re.findall(pattern, formula) def constantesFun(self): - try: - formula = self.division[1] - pattern = r'[-+]?\b\d+(?:\.\d+)?\b' - self.constantes = re.findall(pattern, formula) - except IndexError: - print("No se encontró ninguna constante") - except Exception as e: - print(f"Error en constantes: {e}") + """Detecta y registra constantes numéricas en la fórmula.""" + formula = self.division[1] + pattern = r'[-+]?\b\d+(?:\.\d+)?\b' + self.constantes = re.findall(pattern, formula) def referenciasFun(self): - try: - formula = self.division[1].upper() - # Detectar rangos como A1:B34 - self.rangos = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}:[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) - # Detectar referencias simples (excluyendo las que ya están en rangos) - todas = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) - partes_de_rangos = [celda for r in self.rangos for celda in r.split(":")] - self.referencias = [ref for ref in todas if ref not in partes_de_rangos] - except Exception as e: - print(f"Error en referencias: {e}") - - def imprimirCadenaFun(self): - if self.value: - print("\n--- Resultado ---") - print(f"Funciones encontradas: {self.funciones}") - print(f"Constantes encontradas: {self.constantes}") - print(f"Referencias individuales: {self.referencias}") - print(f"Rangos detectados: {self.rangos}") - print("------------------\n") - else: - print("No puedes imprimir nada. La fórmula no empieza con '='.") + """Detecta y registra referencias y rangos en la fórmula.""" + formula = self.division[1].upper() + self.rangos = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}:[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) + todas = re.findall(r'\b[A-Z]{1,3}[1-9][0-9]{0,4}\b', formula) + partes_de_rangos = [celda for r in self.rangos for celda in r.split(":")] + self.referencias = [ref for ref in todas if ref not in partes_de_rangos] + + def manejarErrores(self): + """Valida las funciones detectadas, lanzando error si son desconocidas.""" + funciones_validas = {"SUMA", "MAX", "MIN", "PROMEDIO", "SI", "CONTAR.SI", "CONCATENAR"} + for funcion in self.funciones: + if funcion not in funciones_validas: + raise ValueError(f"Función desconocida: {funcion}") def direccionamientoFun(self): + """ + Clasifica cada elemento léxico detectado según el orden de evaluación requerido. + + Retorna: + dict: Clasificación ordenada de los elementos léxicos. + """ funciones_basicas = {"SUMA", "MAX", "MIN", "PROMEDIO"} funciones_ext = {"SI", "CONTAR.SI", "CONCATENAR"} - print("\n--- Clasificación y Direccionamiento ---") - for constante in self.constantes: - print(f"🔹 Constante '{constante}' → Evaluación directa") - - for referencia in self.referencias: - print(f"🔹 Referencia '{referencia}' → Resolución de referencia") - - for rango in self.rangos: - print(f"🔹 Rango '{rango}' → Resolución de referencia (rango)") - - for funcion in self.funciones: - if funcion in funciones_basicas: - print(f"🔹 Función básica '{funcion}' → Evaluación funcional") - elif funcion in funciones_ext: - print(f"🔹 Función extendida '{funcion}' → Evaluación funcional") - else: - print(f"❌ Función '{funcion}' no reconocida → Error: función desconocida") + clasificacion = { + "constantes": [(c, "Evaluación directa") for c in self.constantes], + "referencias": [(r, "Resolución de referencia") for r in self.referencias], + "rangos": [(rg, "Resolución de referencia (rango)") for rg in self.rangos], + "funciones": [ + (f, "Evaluación funcional básica") if f in funciones_basicas else + (f, "Evaluación funcional extendida") if f in funciones_ext else + (f, "Desconocida") for f in self.funciones + ] + } - print("-----------------------------------------\n") - + orden_evaluacion = ["constantes", "referencias", "rangos", "funciones"] + return {key: clasificacion[key] for key in orden_evaluacion} def clasificacionFun(self): - if "=" in self.texto: - self.value = True - else: - print("❌ La fórmula no contiene '='.") - return - - try: - self.division = self.texto.split("=", maxsplit=1) - self.funcionesFun() - self.constantesFun() - self.referenciasFun() - self.imprimirCadenaFun() - self.direccionamientoFun() - except Exception as e: - print(f"Ocurrió un error general: {e}") - - - - - -#parte para hacer el test de la prueba logica -while True: - test = input("Ingrese su expresión a valorar (ej: =SUMA(1,A1,B2:B5)): ") - prueba = Logic(test) - prueba.clasificacionFun() - if prueba.value: - break + """ + Valida, analiza y clasifica la fórmula completa. + + Retorna: + dict: Resultado estructurado con clasificación y descripción de elementos. + + Lanza: + ValueError: Si la fórmula no es válida (no comienza con '='). + """ + if "=" not in self.texto: + raise ValueError("La fórmula no comienza con '='") + self.value = True + self.division = self.texto.split("=", maxsplit=1) + self.funcionesFun() + self.constantesFun() + self.referenciasFun() + self.manejarErrores() + return self.direccionamientoFun() + + +# Ejemplo de ejecución +test = "=SUMA(1, A1, B2:B5)" +logica = Logic(test) +try: + resultado = logica.clasificacionFun() + print("--- Resultado ---") + for tipo, elementos in resultado.items(): + for elemento, descripcion in elementos: + print(f"🔹 {tipo.capitalize()} '{elemento}' → {descripcion}") +except ValueError as ve: + print(f"Error: {ve}") diff --git a/test/test_logic.py b/test/test_logic.py new file mode 100644 index 0000000..a2a0754 --- /dev/null +++ b/test/test_logic.py @@ -0,0 +1,29 @@ +# test/test_logic.py +import pytest +import sys +import os +# Añadir al path el directorio src +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'src'))) +from logic import Logic + +def test_formula_valida(): + formula = "=SUMA(1, A1, B2:B5)" + logica = Logic(formula) + resultado = logica.clasificacionFun() + + assert resultado["constantes"] == [("1", "Evaluación directa")] + assert resultado["referencias"] == [("A1", "Resolución de referencia")] + assert resultado["rangos"] == [("B2:B5", "Resolución de referencia (rango)")] + assert resultado["funciones"] == [("SUMA", "Evaluación funcional básica")] + +def test_formula_funcion_desconocida(): + formula = "=FOO(2, B3)" + logica = Logic(formula) + with pytest.raises(ValueError, match="Función desconocida: FOO"): + logica.clasificacionFun() + +def test_formula_sin_igual(): + formula = "SUMA(1,2)" + logica = Logic(formula) + with pytest.raises(ValueError, match="La fórmula no comienza con '='"): + logica.clasificacionFun()