Básicamente, tengo un campo de entrada de usuario donde un usuario puede ingresar un número. También les gustaría poder ingresar ecuaciones en el campo de entrada.

Algo así como "874.45 * 0.825 + 4000" y convertirlo a su valor numérico real.

Todas las soluciones que encontré apuntan al temido método eval () . Especialmente porque este es un campo ingresado por el usuario, me preocupa simplemente ejecutar eval ("874.45 * 0.825 + 4000") y esperar obtener un número en el back-end.

Supongo que podría hacer una llamada de servicio web al servidor (ASP.NET), pero me temo que un ligero retraso creará cierta frustración por parte del usuario.

¿Alguien sabe de una buena técnica o bibliotecas existentes?

4
taco 19 may. 2011 a las 19:45

4 respuestas

La mejor respuesta

Lo que realmente necesita aquí es un "analizador de expresiones", porque está tratando de permitir que los usuarios expresen sus valores utilizando un pequeño lenguaje específico de dominio.

La mecánica básica funciona así:

  1. Tokeniza su expresión en operadores y operandos.

  2. Según el orden de las operaciones (por ejemplo, donde la multiplicación se evalúa con mayor prioridad que la suma), empuje los operadores y operandos a una pila.

  3. Pop los operandos de la pila y empujar resultados intermedios de nuevo en la pila. Repita hasta que la pila esté vacía.

He hecho esto miles de millones de veces para diferentes "pequeños idiomas" a lo largo de mis proyectos. Pero nunca en javascript. Por lo tanto, no puedo recomendar directamente una biblioteca de análisis adecuada.

Pero una búsqueda rápida en Google revela "PEG.js". Compruébalo aquí:

http://pegjs.majda.cz/

Todos los ejemplos en su documentación son exactamente para el tipo de "analizador de expresiones" que está tratando de construir.

4
benjismith 19 may. 2011 a las 15:54

Creo que eval puede presentar un menor riesgo de seguridad si analiza la cadena resultante y valida su contenido para que solo sean dígitos y operadores, y ejecuta la evaluación falsificando las variables de alcance externo como documento, etc. como 'var document = null'.

1
Marino Šimić 19 may. 2011 a las 16:06

Simplemente multiplíquelo por 1 y forzará a javascript a tratarlo como un entero a partir de ese momento.

P.ej

int = '2343.34' * 1;
int = input * 1;
1
Dunhamzzz 19 may. 2011 a las 15:46

¿Y qué tiene de malo el eval en este caso?

En cuanto a mí, encaja perfectamente en tu tarea. Si desea proteger su contexto de ejecución, puede definir funciones como:

function calc(str) {
  var window = null, self = null, document = null;
  // other globals like: $ = null, jQuery = null, etc. 
  try { return eval(str); } catch(e) {...}
}

Y úselo donde necesite interpretar la cadena. Simple y efectivo.

1
c-smile 19 may. 2011 a las 16:03