125 votes

Évaluation d'une chaîne de caractères en tant qu'expression mathématique en JavaScript

Comment analyser et évaluer une expression mathématique dans une chaîne de caractères (par ex. '1+1' ) sans invoquer eval(string) pour obtenir sa valeur numérique ?

Avec cet exemple, je veux que la fonction accepte '1+1' et retourner 2 .

10voto

Avi Points 309

J'ai créé BigEval dans le même but.
Dans la résolution d'expressions, il fonctionne exactement de la même façon que Eval() et supporte les opérateurs comme %, ^, &, ** (puissance) et ! (factorielle). Vous êtes également autorisé à utiliser des fonctions et des constantes (ou dites variables) à l'intérieur de l'expression. L'expression est résolue en Commande de PEMDAS ce qui est courant dans les langages de programmation, notamment 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

Il est également possible d'utiliser ces bibliothèques de grands nombres pour l'arithmétique si vous avez affaire à des nombres d'une précision arbitraire.

9voto

Itangalo Points 100

Je me suis mis à la recherche de bibliothèques JavaScript pour évaluer les expressions mathématiques, et j'ai trouvé ces deux candidats prometteurs :

  • Évaluateur d'expressions JavaScript : Plus petit et, espérons-le, plus léger. Permet les expressions algébriques, les substitutions et un nombre de fonctions.

  • mathjs : Permet également les nombres complexes, les matrices et les unités. Construit pour être utilisé à la fois par JavaScript dans le navigateur et Node.js.

8voto

RichK Points 1914

J'ai récemment fait cela en C# (pas de Eval() pour nous...) en évaluant l'expression en Notation polonaise inversée (c'est la partie la plus facile). La partie la plus difficile consiste à analyser la chaîne et à la transformer en notation polonaise inversée. J'ai utilisé le fichier Algorithme de la gare de triage car il existe un excellent exemple sur Wikipedia et un pseudo-code. J'ai trouvé qu'il était très simple de mettre en œuvre les deux et je le recommande si vous n'avez pas encore trouvé de solution ou si vous cherchez des alternatives.

8voto

jMichael Points 21

Voici une petite fonction que je viens de créer pour résoudre ce problème. Elle construit l'expression en analysant la chaîne de caractères un par un (c'est en fait assez rapide). Elle prend n'importe quelle expression mathématique (limitée aux opérateurs +,-,*,/) et renvoie le résultat. Il peut également gérer les valeurs négatives et les opérations numériques illimitées.

La seule chose à faire est de s'assurer qu'il calcule * & / avant + & -. J'ajouterai cette fonctionnalité plus tard, mais pour l'instant, ceci fait ce dont j'ai besoin...

/**
* 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;
}

4voto

GalaxyCat105 Points 2107

Vous pourriez utiliser une boucle for pour vérifier si la chaîne contient des caractères non valides, puis utiliser un try...catch avec eval pour vérifier si le calcul génère une erreur, par exemple eval("2++") serait.

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'))

ou au lieu d'une fonction, vous pourriez définir 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'))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X