dinamicas convert array alternativa javascript string math numbers

convert - Evaluar una cadena como una expresión matemática en JavaScript



string javascript (14)

¿Cómo puedo analizar y evaluar una expresión matemática en una cadena (por ejemplo, ''1+1'' ) sin invocar eval(string) para obtener su valor numérico?

Con ese ejemplo, quiero que la función acepte ''1+1'' y devuelva 2 .


// Puedes hacer + o - fácilmente:

function addbits(s){ var total= 0, s= s.match(/[+/-]*(/./d+|/d+(/./d+)?)/g) || []; while(s.length){ total+= parseFloat(s.shift()); } return total; } var string=''1+23+4+5-30''; addbits(string)

Las matemáticas más complicadas hacen que eval sea más atractivo y, por cierto, más simple de escribir.


Alguien tiene que analizar esa cadena. Si no es el intérprete (a través de eval ), entonces tendrá que ser usted quien escriba una rutina de análisis para extraer números, operadores y cualquier otra cosa que quiera respaldar en una expresión matemática.

Entonces, no, no hay ninguna forma (simple) sin eval . Si le preocupa la seguridad (porque la entrada que está analizando no proviene de una fuente que usted controla), ¿tal vez puede verificar el formato de la entrada (a través de un filtro de expresión regular de la lista blanca) antes de pasarlo a eval ?


Aquí hay una solución algorítmica similar a la de jMichael que recorre la expresión carácter por carácter y progresivamente rastrea a la izquierda / operador / derecha. La función acumula el resultado después de cada turno, encuentra un carácter de operador. Esta versión solo es compatible con los operadores ''+'' y ''-'', pero está escrita para ser extendida con otros operadores. Nota: establecemos ''currOp'' en ''+'' antes de un bucle porque suponemos que la expresión comienza con un flotante positivo. De hecho, en general estoy asumiendo que la entrada es similar a lo que vendría de una calculadora.

function calculate(exp) { const opMap = { ''+'': (a, b) => { return parseFloat(a) + parseFloat(b) }, ''-'': (a, b) => { return parseFloat(a) - parseFloat(b) }, }; const opList = Object.keys(opMap); let acc = 0; let next = ''''; let currOp = ''+''; for (let char of exp) { if (opList.includes(char)) { acc = opMap[currOp](acc, next); currOp = char; next = ''''; } else { next += char; } } return currOp === ''+'' ? acc + parseFloat(next) : acc - parseFloat(next); }


Creo que parseInt y ES6 pueden ser útiles en esta situación

==> de esta manera:

let func = (str) => { let arr = str.split(""); return `${Number(arr[0]) + parseInt(arr[1] + Number(arr[2]))}`}; console.log(func("1+1"));

Lo principal aquí es que parseInt analiza el número con el operador. El código se puede modificar a las necesidades correspondientes.


Esta es una pequeña función que armé hace un momento para resolver este problema: construye la expresión analizando la cadena un carácter a la vez (en realidad es bastante rápido). Esto tomará cualquier expresión matemática (limitada a +, -, *, / operadores solamente) y devolverá el resultado. También puede manejar valores negativos y operaciones de números ilimitados.

El único "por hacer" que queda es asegurarse de que calcula * y / antes de + y -. Agregaré esa funcionalidad más adelante, pero por ahora esto hace lo que necesito ...

/** * Evaluate a mathematical expression (as a string) and return the result * @param {String} expr A mathematical expression * @returns {Decimal} Result of the mathematical expression * @example * // Returns -81.4600 * expr("10.04+9.5-1+-100"); */ function expr (expr) { var chars = expr.split(""); var n = [], op = [], index = 0, oplast = true; n[index] = ""; // Parse the expression for (var c = 0; c < chars.length; c++) { if (isNaN(parseInt(chars[c])) && chars[c] !== "." && !oplast) { op[index] = chars[c]; index++; n[index] = ""; oplast = true; } else { n[index] += chars[c]; oplast = false; } } // Calculate the expression expr = parseFloat(n[0]); for (var o = 0; o < op.length; o++) { var num = parseFloat(n[o + 1]); switch (op[o]) { case "+": expr = expr + num; break; case "-": expr = expr - num; break; case "*": expr = expr * num; break; case "/": expr = expr / num; break; } } return expr; }


Eventualmente me he ido por esta solución, que funciona para sumar enteros positivos y negativos (y con una pequeña modificación en la expresión regular también funcionará para los decimales):

function sum(string) { return (string.match(/^(-?/d+)(/+-?/d+)*$/)) ? string.split(''+'').stringSum() : NaN; } Array.prototype.stringSum = function() { var sum = 0; for(var k=0, kl=this.length;k<kl;k++) { sum += +this[k]; } return sum; }

No estoy seguro de si es más rápido que eval (), pero como tengo que llevar a cabo la operación muchas veces, me siento mucho más cómodo ejecutando este script que creando muchas instancias del compilador de JavaScript.


Fui en busca de bibliotecas de JavaScript para evaluar expresiones matemáticas, y encontré estos dos candidatos prometedores:

  • Evaluador de expresiones de JavaScript : más pequeño y, con suerte, más liviano. Permite expresiones algebraicas, sustituciones y una serie de funciones.

  • mathjs : también permite números complejos, matrices y unidades. Creado para ser utilizado tanto por JavaScript dentro del navegador como por Node.js.


Prueba nerdamer

var result = nerdamer(''12+2+PI'').evaluate(); document.getElementById(''text'').innerHTML = result.text();

<script src="http://nerdamer.com/js/nerdamer.core.js"></script> <div id="text"></div>


Pruebe AutoCalculator https://github.com/JavscriptLab/autocalculate Calcular el valor y la salida de las entradas mediante el uso de expresiones de selector

Simplemente agregue un atributo para su entrada de salida como data-ac = "(# firstinput + # secondinput)"

No es necesario inicializar nada, solo agregue el atributo data-ac. Descubrirá los elementos añadidos dinámicamente de forma automática

Para agregar ''Rs'' con Salida solo agregue dentro del soporte de datos rizado-ac = "{Rs} (# firstinput + # secondinput)"


Puede usar la biblioteca JavaScript Expression Evaluator , que le permite hacer cosas como:

Parser.evaluate("2 ^ x", { x: 3 });

O mathjs , que permite cosas como:

math.eval(''sin(45 deg) ^ 2'');

Terminé eligiendo mathjs para uno de mis proyectos.


Recientemente hice esto en C # (sin Eval () para nosotros ...) al evaluar la expresión en Notación Polaca Inversa (ese es el bit fácil). La parte difícil es en realidad analizar esta cadena y convertirla en Notación Polaca Inversa. Utilicé el algoritmo de Shunting Yard ya que hay un gran ejemplo en Wikipedia y un pseudocódigo. Me pareció muy fácil de implementar y lo recomendaría si aún no ha encontrado una solución o está buscando alternativas.


Una alternativa a la excelente respuesta de @kennebec, utilizando una expresión regular más corta y permitiendo espacios entre operadores

function addbits(s) { var total = 0; s = s.replace(//s/g, '''').match(/[+/-]?([0-9/./s]+)/g) || []; while(s.length) total += parseFloat(s.shift()); return total; }

Úselo como

addbits(''5 + 30 - 25.1 + 11'');

Actualizar

Aquí hay una versión más optimizada

function addbits(s) { return (s.replace(//s/g, '''').match(/[+/-]?([0-9/.]+)/g) || []) .reduce(function(sum, value) { return parseFloat(sum) + parseFloat(value); }); }


BigEval para el mismo propósito.
Al resolver expresiones, realiza exactamente lo mismo que Eval() y admite operadores como%, ^, &, ** (potencia) y! (factorial). También se le permite usar funciones y constantes (o decir variables) dentro de la expresión. La expresión se resuelve en orden PEMDAS, que es común en lenguajes de programación, incluido JavaScript.

var Obj = new BigEval(); var result = Obj.exec("5! + 6.6e3 * (PI + E)"); // 38795.17158152233 var result2 = Obj.exec("sin(45 * deg)**2 + cos(pi / 4)**2"); // 1 var result3 = Obj.exec("0 & -7 ^ -7 - 0%1 + 6%2"); //-7

También se puede hacer para usar esas bibliotecas de números grandes para la aritmética en caso de que se trate de números con precisión arbitraria.


const getAddition = (str) => { return str.split(''+'').reduce((total, num) => (total + num * 1), 0); }; const addition = getAddition(''1+1'');

Además es 2.