Pregunta

Todo lo que necesito es verificar, usar Python, si una cadena es una expresión matemática válida o no.

Por simplicidad, digamos que solo necesito + - * / operadores (+ - como unary también) con números y paréntesis anidado. También agrego nombres de variables simples para la integridad.

Para que pueda probar de esta manera:

test("-3 * (2 + 1)") #valid
test("-3 * ")        #NOT valid

test("v1 + v2")      #valid
test("v2 - 2v")      #NOT valid ("2v" not a valid variable name)

Lo intenté pyparsing Pero solo probando el ejemplo: "Parser de expresión algebraica simple, que funciona +,-,*,/ y ^ operaciones aritmeticas" Me pasan un código no válido y también tratando de solucionarlo, siempre me equivoco sintaxis que se analizan sin elevar excepciones

sólo inténtalo:

>>>test('9', 9)
9 qwerty = 9.0 ['9'] => ['9']
>>>test('9 qwerty', 9)
9 qwerty = 9.0 ['9'] => ['9']

Ambas pruebas pasan ... o_o

¿Algún consejo?

¿Fue útil?

Solución

Esto se debe a que el código PyParsing permite funciones. (Y por cierto, hace mucho más de lo que necesitas, es decir, crea una pila y evalúa eso).

Para empezar, podrías eliminar pi y ident (Y posiblemente algo más que me falta en este momento) del código para no permitir los personajes.

La razón es diferente: los analizadores de PyParsing no intentarán consumir toda la entrada de forma predeterminada. Tienes que agregar + StringEnd() (e importarlo, por supuesto) hasta el final de expr Para que falle si no puede analizar toda la entrada. En ese caso, pyparsing.ParseException será levantado. (Fuente: http://pyparsing-public.wikispaces.com/faqs)

Si le importa aprender un poco de análisis, lo que necesita puede construirse propensamente en menos de treinta líneas con cualquier biblioteca de análisis decente (me gusta Lepl).

Otros consejos

Puede intentar construir un analizador simple para tokenizar la cadena de la expresión aritmética y luego construir un árbol de expresión, si el árbol es válido (las hojas son todas operandas y los nodos internos son todos operadores), entonces puede decir que la expresión es válido.

El concepto básico es hacer algunas funciones auxiliares para crear su analizador.

def extract() obtendrá el próximo personaje de la expresión
def peek() Similar al extracto pero usado si no hay espacio en blanco para verificar el siguiente carácter
get_expression()
get_next_token()

Alternativamente, si puede garantizar el espacio en blanco entre los personajes que podría usar split() hacer toda la tokenización.

Luego construye su árbol y evalúa si está estructurado correctamente

Prueba esto para más información: http://effbot.org/zone/simple-pop-dodow-parsing.htm

¿Por qué no simplemente evaluarlo y atrapar el error de sintaxis?

from math import *

def validateSyntax(expression):
  functions = {'__builtins__': None}
  variables = {'__builtins__': None}

  functions = {'acos': acos,
               'asin': asin,
               'atan': atan,
               'atan2': atan2,
               'ceil': ceil,
               'cos': cos,
               'cosh': cosh,
               'degrees': degrees,
               'exp': exp,
               'fabs':fabs,
               'floor': floor,
               'fmod': fmod,
               'frexp': frexp,
               'hypot': hypot,
               'ldexp': ldexp,
               'log': log,
               'log10': log10,
               'modf': modf,
               'pow': pow,
               'radians': radians,
               'sin': sin,
               'sinh': sinh,
               'sqrt': sqrt,
               'tan': tan,
               'tanh': tanh}

  variables = {'e': e, 'pi': pi}

  try:
    eval(expression, variables, functions)
  except (SyntaxError, NameError, ZeroDivisionError):
    return False
  else:
    return True

Aquí hay algunas muestras:

> print validSyntax('a+b-1') # a, b are undefined, so a NameError arises.
> False

> print validSyntax('1 + 2')
> True

> print validSyntax('1 - 2')
> True

> print validSyntax('1 / 2')
> True

> print validSyntax('1 * 2')
> True

> print validSyntax('1 +/ 2')
> False

> print validSyntax('1 + (2')
> False

> print validSyntax('import os')
> False

> print validSyntax('print "asd"')
> False

> print validSyntax('import os; os.delete("~\test.txt")')
> False # And the file was not removed

Está restringido solo a operaciones matemáticas, por lo que debería trabajar un poco mejor que un crudo eval.

Suplente parseAll=True a la llamada a parseString convertirá este analizador en un validador.

Si está interesado en modificar un motor de evaluación de matemáticas personalizadas escritas en Python para que sea un validador, puede comenzar con Evaluador 2.0 (Python 3.x) y Math_evaluator (Python 2.x). No son soluciones preparadas, pero le permitirían personalizar completamente lo que sea que esté tratando de hacer exactamente utilizando (con suerte) el código Python fácil de leer. Tenga en cuenta que "y" & "o" son tratados como operadores.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top