Skip to content

Feature/errores evaluacion #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -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
109 changes: 109 additions & 0 deletions src/logic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import re

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 = []
self.funciones = []
self.referencias = []
self.rangos = []
self.value = False

def funcionesFun(self):
"""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):
"""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):
"""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"}

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
]
}

orden_evaluacion = ["constantes", "referencias", "rangos", "funciones"]
return {key: clasificacion[key] for key in orden_evaluacion}

def clasificacionFun(self):
"""
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}")
29 changes: 29 additions & 0 deletions test/test_logic.py
Original file line number Diff line number Diff line change
@@ -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()