Wie analysiere und bewerte ich einen mathematischen Ausdruck in einer Zeichenfolge (z. B. '1+1'
), ohne ihn aufzurufen eval(string)
, um seinen numerischen Wert zu erhalten?
In diesem Beispiel möchte ich, dass die Funktion akzeptiert '1+1'
und zurückgibt 2
.
javascript
string
math
numbers
whereesrhys
quelle
quelle
(Function("return 1+1;"))()
.Antworten:
Sie können die JavaScript Expression Evaluator-Bibliothek verwenden , mit der Sie Folgendes tun können:
Parser.evaluate("2 ^ x", { x: 3 });
Oder mathjs , was Dinge erlaubt wie:
math.eval('sin(45 deg) ^ 2');
Am Ende habe ich Mathjs für eines meiner Projekte ausgewählt.
quelle
Sie können + oder - einfach tun:
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'; console.log( addbits(string) )
Kompliziertere Mathematik macht eval attraktiver - und sicherlich einfacher zu schreiben.
quelle
Jemand muss diese Zeichenfolge analysieren. Wenn es nicht der Interpreter (via
eval
) ist, müssen Sie es sein und eine Parsing-Routine schreiben, um Zahlen, Operatoren und alles andere zu extrahieren, das Sie in einem mathematischen Ausdruck unterstützen möchten.Also, nein, es gibt keinen (einfachen) Weg ohne
eval
. Wenn Sie sich Sorgen um die Sicherheit machen (weil die Eingabe, die Sie analysieren, nicht von einer Quelle stammt, die Sie steuern), können Sie möglicherweise das Format der Eingabe (über einen Regex-Filter für die Whitelist) überprüfen, bevor Sie sie an übergebeneval
?quelle
Eine Alternative zur hervorragenden Antwort von @kennebec, bei der ein kürzerer regulärer Ausdruck verwendet wird und Leerzeichen zwischen Operatoren zugelassen werden
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; }
Verwenden Sie es wie
addbits('5 + 30 - 25.1 + 11');
Aktualisieren
Hier ist eine optimierte Version
function addbits(s) { return (s.replace(/\s/g, '').match(/[+\-]?([0-9\.]+)/g) || []) .reduce(function(sum, value) { return parseFloat(sum) + parseFloat(value); }); }
quelle
Ich habe BigEval für den gleichen Zweck erstellt.
Beim Lösen von Ausdrücken funktioniert es genauso wie
Eval()
Operatoren wie%, ^, &, ** (Potenz) und! (Fakultät). Sie können auch Funktionen und Konstanten (oder Variablen) innerhalb des Ausdrucks verwenden. Der Ausdruck wird in der PEMDAS-Reihenfolge gelöst , die in Programmiersprachen einschließlich JavaScript üblich ist.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
Es kann auch vorgenommen werden, diese Big Number-Bibliotheken für die Arithmetik zu verwenden, falls Sie mit Zahlen mit beliebiger Genauigkeit arbeiten.
quelle
Ich suchte nach JavaScript-Bibliotheken zur Bewertung mathematischer Ausdrücke und fand diese beiden vielversprechenden Kandidaten:
JavaScript Expression Evaluator : Kleiner und hoffentlich leichter. Ermöglicht algebraische Ausdrücke, Substitutionen und eine Reihe von Funktionen.
mathjs : Ermöglicht auch komplexe Zahlen, Matrizen und Einheiten. Entwickelt, um sowohl von JavaScript im Browser als auch von Node.js verwendet zu werden.
quelle
Ich habe dies kürzlich in C # getan (nein
Eval()
für uns ...), indem ich den Ausdruck in umgekehrter polnischer Notation ausgewertet habe (das ist das einfache Stück). Der schwierige Teil besteht darin, die Zeichenfolge zu analysieren und in die umgekehrte polnische Notation umzuwandeln. Ich habe den Shunting Yard-Algorithmus verwendet , da es ein großartiges Beispiel für Wikipedia und Pseudocode gibt. Ich fand es sehr einfach, beide zu implementieren, und ich würde dies empfehlen, wenn Sie noch keine Lösung gefunden haben oder nach Alternativen suchen.quelle
Dies ist eine kleine Funktion, die ich gerade zusammengestellt habe, um dieses Problem zu lösen. Sie baut den Ausdruck auf, indem die Zeichenfolge zeichenweise analysiert wird (eigentlich ist sie jedoch ziemlich schnell). Dies nimmt jeden mathematischen Ausdruck (beschränkt auf +, -, *, / Operatoren) und gibt das Ergebnis zurück. Es kann auch negative Werte und unbegrenzte Zahlenoperationen verarbeiten.
Sie müssen nur noch sicherstellen, dass * & / vor + & - berechnet wird. Ich werde diese Funktionalität später hinzufügen, aber im Moment macht das, was ich brauche ...
/** * 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; }
quelle
Einfach und elegant mit
Function()
function parse(str) { return Function(`'use strict'; return (${str})`)() } parse("1+2+3");
quelle
) -----
() `diese Klammer endlich?parse('process.exit()')
.Sie können eine for-Schleife verwenden, um zu überprüfen, ob die Zeichenfolge ungültige Zeichen enthält, und dann einen try ... catch mit eval verwenden, um zu überprüfen, ob die Berechnung einen Fehler wie folgt auslöst
eval("2++")
.function evaluateMath(str) { for (var i = 0; i < str.length; i++) { if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) { return NaN; } } try { return eval(str) } catch (e) { if (e.name !== 'SyntaxError') throw e return NaN; } } console.log(evaluateMath('2 + 6'))
oder anstelle einer Funktion können Sie einstellen
Math.eval
Math.eval = function(str) { for (var i = 0; i < str.length; i++) { if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) { return NaN; } } try { return eval(str) } catch (e) { if (e.name !== 'SyntaxError') throw e return NaN; } } console.log(Math.eval('2 + 6'))
quelle
Ich habe mich schließlich für diese Lösung entschieden, die zum Summieren positiver und negativer Ganzzahlen funktioniert (und mit einer kleinen Änderung des regulären Ausdrucks auch für Dezimalstellen funktioniert):
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; }
Ich bin mir nicht sicher, ob es schneller als eval () ist, aber da ich die Operation oft ausführen muss, ist es für mich weitaus komfortabler, dieses Skript auszuführen, als viele Instanzen des Javascript-Compilers zu erstellen
quelle
return
nicht innerhalb eines Ausdrucks verwendet werden,sum("+1")
gibt NaN .Versuchen Sie es mit 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>
quelle
Ich glaube das
parseInt
und ES6 kann in dieser Situation hilfreich seinlet func = (str) => { let arr = str.split(""); return `${Number(arr[0]) + parseInt(arr[1] + Number(arr[2]))}`}; console.log(func("1+1"));
Die Hauptsache hier ist, dass
parseInt
die Nummer mit dem Operator analysiert wird. Der Code kann an die entsprechenden Anforderungen angepasst werden.quelle
Sie können diese gut gepflegte Bibliothek von Github verwenden, die sowohl auf Nodejs als auch auf dem Browser funktioniert und schneller ist als andere hier bereitgestellte alternative Bibliotheken
Verwendung
mexp = require('math-expression-evaluator') var value = mexp.eval(exp);
Vollständige Dokumentation
quelle
Versuchen Sie AutoCalculator https://github.com/JavscriptLab/autocalculate Berechnen Sie den Eingabewert und die Ausgabe mithilfe von Auswahlausdrücken
Fügen Sie einfach ein Attribut für Ihre Ausgabeeingabe hinzu, z. B. data-ac = "(# firstinput + # secondinput)"
Keine Initialisierung erforderlich. Fügen Sie nur das Attribut data-ac hinzu. Dynamisch hinzugefügte Elemente werden automatisch ermittelt
Für das Hinzufügen von 'Rs' mit der Ausgabe fügen Sie einfach die geschweifte Klammer hinzu data-ac = "{Rs} (# firstinput + # secondinput)"
quelle
const operatorToFunction = { "+": (num1, num2) => +num1 + +num2, "-": (num1, num2) => +num1 - +num2, "*": (num1, num2) => +num1 * +num2, "/": (num1, num2) => +num1 / +num2 } const findOperator = (str) => { const [operator] = str.split("").filter((ch) => ["+", "-", "*", "/"].includes(ch)) return operator; } const executeOperation = (str) => { const operationStr = str.replace(/[ ]/g, ""); const operator = findOperator(operationStr); const [num1, num2] = operationStr.split(operator) return operatorToFunction[operator](num1, num2); }; const addition = executeOperation('1 + 1'); // ans is 2 const subtraction = executeOperation('4 - 1'); // ans is 3 const multiplication = executeOperation('2 * 5'); // ans is 10 const division = executeOperation('16 / 4'); // ans is 4
quelle
num
mit 1 multiplizieren ?Hier ist eine algorithmische Lösung ähnlich der von jMichael, die den Ausdruck Zeichen für Zeichen durchläuft und nach und nach links / Operator / rechts verfolgt. Die Funktion sammelt das Ergebnis nach jeder Runde, in der sie ein Operatorzeichen findet. Diese Version unterstützt nur die Operatoren '+' und '-', ist jedoch so geschrieben, dass sie mit anderen Operatoren erweitert werden kann. Hinweis: Wir setzen 'currOp' vor dem Looping auf '+', da wir davon ausgehen, dass der Ausdruck mit einem positiven Float beginnt. Insgesamt gehe ich davon aus, dass die Eingabe der eines Taschenrechners ähnelt.
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); }
quelle