it-swarm.com.de

Eine Zeichenfolge als mathematischen Ausdruck in JavaScript auswerten

Wie kann ich einen mathematischen Ausdruck in einer Zeichenfolge (z. B. '1+1') analysieren und auswerten, ohne eval(string) aufzurufen, um seinen numerischen Wert zu erhalten?

In diesem Beispiel möchte ich, dass die Funktion '1+1' akzeptiert und 2 zurückgibt.

53
wheresrhys

Ich habe mich letztendlich für diese Lösung entschieden, die positive und negative ganze Zahlen summiert (und mit ein wenig Änderung des regulären Ausdrucks auch für Dezimalzahlen 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 nicht sicher, ob es schneller ist als eval (), aber da ich die Operation viele Male ausführen muss, ist es viel komfortabler, dieses Skript auszuführen, als das Erstellen von Instanzen des Javascript-Compilers

2
wheresrhys

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 wie erlaubt:

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

Am Ende wählte ich mathjs für eines meiner Projekte.

52
Rafael Vega

// Sie können + oder - leicht 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';
addbits(string)

Eine kompliziertere Mathematik macht eval attraktiver und sicherlich einfacher zu schreiben.

18
kennebec

Jemand muss diese Zeichenfolge analysieren. Wenn es nicht der Interpreter ist (über eval), müssen Sie es selbst sein und eine Parsing-Routine schreiben, um Zahlen, Operatoren und alles andere zu extrahieren, das Sie in einem mathematischen Ausdruck unterstützen möchten.

Nein, es gibt keinen (einfachen) Weg ohne eval. Wenn Sie sich Sorgen um die Sicherheit machen (da die Eingabe, die Sie analysieren, nicht von einer Quelle stammt, die Sie kontrollieren), können Sie möglicherweise das Format der Eingabe überprüfen (über einen Whitelist-Regex-Filter), bevor Sie sie an eval übergeben.

17
bdukes

Ich suchte nach JavaScript-Bibliotheken zur Auswertung mathematischer Ausdrücke und fand diese beiden vielversprechenden Kandidaten:

  • JavaScript Expression Evaluator : Kleiner und hoffentlich mehr Leichtgewicht. Ermöglicht algebraische Ausdrücke, Ersetzungen und eine Anzahl von Funktionen.

  • mathjs : Erlaubt auch komplexe Zahlen, Matrizen und Einheiten.

7
Itangalo

Ich habe dies kürzlich in C # (kein Eval () für uns ...) getan, indem ich den Ausdruck in der polnischen Umkehrnotation (das ist das einfache Bit) ausgewertet hat. Der schwierige Teil besteht eigentlich darin, die Saite zu parsen und in Reverse Polish Notation umzuwandeln. Ich habe den Shunting Yard-Algorithmus verwendet, da es auf Wikipedia und Pseudocode ein gutes Beispiel gibt. Ich fand es sehr einfach, beides zu implementieren, und ich würde es empfehlen, wenn Sie noch keine Lösung gefunden haben oder nach Alternativen suchen.

6
RichK

Ich habe BigEval für denselben Zweck erstellt.
Beim Lösen von Ausdrücken verhält es sich genauso wie Eval() und unterstützt Operatoren wie%, ^, &, ** (power) und! (factorial) . Sie dürfen auch Funktionen und Konstanten (oder Variablen) innerhalb des Ausdrucks verwenden. Der Ausdruck wird in PEMDAS-Reihenfolge gelöst , die in Programmiersprachen einschließlich JavaScript häufig vorkommt.

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 ist auch möglich, diese Big Number-Bibliotheken für die Arithmetik zu verwenden, falls Sie mit Zahlen mit beliebiger Genauigkeit arbeiten.

6
Avi

Dies ist eine kleine Funktion, die ich gerade zusammengeworfen habe, um dieses Problem zu lösen. Sie baut den Ausdruck auf, indem die Zeichenfolge einzeln analysiert wird. Dies nimmt jeden mathematischen Ausdruck (begrenzt auf +, -, *, /) und gibt das Ergebnis zurück. Es kann auch negative Werte und unbegrenzte Anzahl von Operationen verarbeiten.

Jetzt müssen Sie nur noch sicherstellen, dass * und/vor + und - berechnet wird. Fügt diese Funktionalität später hinzu, aber jetzt tut dies, 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;
}
4
jMichael

Eine Alternative zu der hervorragenden Antwort von @kennebec, die einen kürzeren regulären Ausdruck verwendet und Leerzeichen zwischen Operatoren zulässt 

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 gerne

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

Update

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);
        });
}
4
Stefan Gabos

Versuchen Sie 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>

2
ArchHaskeller

Versuchen Sie es mit 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 Ausgabe hinzu, beispielsweise Data-ac = "(# firstinput + # secondinput)"

Es ist keine Initialisierung erforderlich. Fügen Sie nur das data-ac-Attribut hinzu .. __ Es werden automatisch hinzugefügte Elemente automatisch ermittelt

Zum Hinzufügen von 'Rs' mit Output fügen Sie einfach die geschweifte Klammer hinzu Data-ac = "{Rs} (# firstinput + # secondinput)"

1
Justin Jose

Ich glaube, dass parseInt und ES6 in dieser Situation hilfreich sein können 

==> auf diese Weise: 

let 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 parst. Der Code kann an die entsprechenden Anforderungen angepasst werden.

1
fuser

Hier ist eine algorithmische Lösung ähnlich der von Michael Michael, die den Ausdruck zeichenweise durchläuft und nach links/Operator/rechts verfolgt. Die Funktion sammelt das Ergebnis nach jeder Runde, in der ein Bedienerzeichen gefunden wird. Diese Version unterstützt nur '+' und '-' Operatoren, ist jedoch so geschrieben, dass sie mit anderen Operatoren erweitert werden kann. Hinweis: Wir setzen 'currOp' vor der Schleife auf '+', weil wir davon ausgehen, dass der Ausdruck mit einem positiven Fließkomma beginnt. Insgesamt gehe ich davon aus, dass die Eingabe ähnlich ist wie bei einem Taschenrechner. 

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);
}
0
internetross
const getAddition = (str) => {
  return str.split('+').reduce((total, num) => (total + num * 1), 0);
};

const addition = getAddition('1+1');

zusatz ist 2.

0