• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

[GELOEST] eval()?

Oliver77

Mitglied
Hi @all meine nächste Spielidee steht. Man hat 4 Zahlen und durch multiplizieren, teilen mal nehmen und geteilt muss man die gewünschte Zahl herausbekommen.
Hier würde sich eval ja anbieten:
Javascript:
let x = 10;
let y = 20;
let text = "x * y";
let result = eval(text);

Aber man soll ja die Finger von eval lassen, wie würdet ihr das angehen?

LG
 
Werbung:
Werbung:
Code:
str = "output1.innerText='zzz'";
Verstehe den Codeschnipsel nicht...

So ich werd ne Funktion machen, die das evaluiert.
Aber folgendes Problem:
Javascript:
\d+(?=\+)

funktioniert auf https://regex101.com/
Aber im Javascript nicht, ist es falsch escaped?

Aufgabe des Regex ist den Operand vor dem Plus-Zeichen zu finden.

Ah hab's hinbekommen
Javascript:
var str = "3+12/3*2";
const reg = /\d+(?=\+)/;
const myArray = reg.exec(str);
ergibt 3

So habe jetzt ne Funktion geschrieben, es gibt kein Punkt vor Strich, das wäre für das Mathe-Spiel unpassend, außerdem wird nur mit ganzzahligen Resultaten gearbeitet.
Javascript:
  function calculateFromString(str) {

                var sum = 0;
                workingString = str;

                function evaluateString() {
                    signList = [];
                    if (workingString.indexOf("*") != -1) {
                        signList.push(workingString.indexOf("*"));
                    }
                    if (workingString.indexOf("/") != -1) {
                        signList.push(workingString.indexOf("/"));
                    }
                    if (workingString.indexOf("+") != -1) {
                        signList.push(workingString.indexOf("+"));
                    }
                    if (workingString.indexOf("-") != -1) {
                        signList.push(workingString.indexOf("-"));
                    }
                    firstSign = Math.min(...signList);
                    switch (workingString[firstSign]) {
                        case "*":
                            regex(/\d+(?=\*)/, /(?<=\*)\d+/, /\d+\*[0-9]+/, "multiply");
                            break;
                        case "+":
                            regex(/\d+(?=\+)/, /(?<=\+)\d+/, /\d+\+[0-9]+/, "plus");
                            break;
                        case "-":
                            regex(/\d+(?=\-)/, /(?<=\-)\d+/, /\d+\-[0-9]+/, "minus");
                            break;
                        case "/":
                            regex(/\d+(?=\/)/, /(?<=\/)\d+/, /\d+\/[0-9]+/, "divide");
                    }
                }
                function regex(regexOperand1, regexOperand2, regexReplace, modus) {

                    var op1 = regexOperand1.exec(workingString);
                    var op2 = regexOperand2.exec(workingString);

                    switch (modus) {
                        case "divide":
                            sum = parseInt(op1) / parseInt(op2);
                            break;
                        case "plus":
                            sum = parseInt(op1) + parseInt(op2);
                            break;
                        case "multiply":
                            sum = parseInt(op1) * parseInt(op2);
                            break;
                        case "minus":
                            sum = parseInt(op1) - parseInt(op2);
                            break;
                    }
                    var repPattern = regexReplace.exec(workingString);
                    workingString = workingString.replace(repPattern, sum);
                }
                const regCount = /\d+/g;
                var signListCount= str.replaceAll(regCount, "");
                var p = parseInt(signListCount.length);
                for (i = 0; i < p; i++) {
                    evaluateString()
                }
                return sum;
            }
         
            document.getElementById("output1").innerText=calculateFromString("6*2/3*2*3-12");

https://codepen.io/Oliver7777/pen/eYLNPGy
 
Zuletzt bearbeitet:
Werbung:
Werbung:
Ja ist mir schon klar, aber für's Spiel ist es nicht gut, man rechnet sich Schritt vor Schritt vorwärts....
Egal wie, wenn Rechenoperationen anstehen, und grundlegender Bestandteil eines Spiels sind, sollte man sich nicht über die allgemein gültigen, und einst i.d. Grundschule erlernten, Konventionen/Regeln hinwegsetzen...

...das sorgt am Ende beim Anwender nur für Verwirrung und Mißmut!

Es sei denn, Du befreist ihn davon durch Deine dezidiert beschriebenen Spielregeln, die sich über den konventionellen Algorithmus der Mathematik hinwegsetzen :D
 
Werbung:
So der Vollständigkeit halber mit Punkt vor Strich Regelung:
Javascript:
           function calc(str) {
                var workingString = str;
                function multiAndDivideFirst() {
                    var onlyDivideAndMultiply = /[^\-\+\"]+[\/\*]+\d/g;
                    var pattern = onlyDivideAndMultiply.exec(workingString) + "";
                    var part = calculateFromString(pattern);
                    workingString = workingString.replace(pattern, part);
                }
                while (workingString.indexOf("/") != -1 || workingString.indexOf("*") != -1) {
                    multiAndDivideFirst();
                }
                if(workingString.indexOf("+") != -1 || workingString.indexOf("-") != -1) {
                    var r = calculateFromString(workingString);
                }
                else  {
                    var r = workingString;
                }
                return r;
            }


            function calculateFromString(str) {

                var sum = 0;
                workingString = str;

                function evaluateString() {
                    signList = [];
                    if (workingString.indexOf("*") != -1) {
                        signList.push(workingString.indexOf("*"));
                    }
                    if (workingString.indexOf("/") != -1) {
                        signList.push(workingString.indexOf("/"));
                    }
                    if (workingString.indexOf("+") != -1) {
                        signList.push(workingString.indexOf("+"));
                    }
                    if (workingString.indexOf("-") != -1) {
                        signList.push(workingString.indexOf("-"));
                    }
                    firstSign = Math.min(...signList);
                    switch (workingString[firstSign]) {
                        case "*":
                            regex(/\d+(?=\*)/, /(?<=\*)\d+/, /\d+\*[0-9]+/, "multiply");
                            break;
                        case "+":
                            regex(/\d+(?=\+)/, /(?<=\+)\d+/, /\d+\+[0-9]+/, "plus");
                            break;
                        case "-":
                            regex(/\d+(?=\-)/, /(?<=\-)\d+/, /\d+\-[0-9]+/, "minus");
                            break;
                        case "/":
                            regex(/\d+(?=\/)/, /(?<=\/)\d+/, /\d+\/[0-9]+/, "divide");
                    }
                }
                function regex(regexOperand1, regexOperand2, regexReplace, modus) {

                    var op1 = regexOperand1.exec(workingString);
                    var op2 = regexOperand2.exec(workingString);

                    switch (modus) {
                        case "divide":
                            sum = parseInt(op1) / parseInt(op2);
                            break;
                        case "plus":
                            sum = parseInt(op1) + parseInt(op2);
                            break;
                        case "multiply":
                            sum = parseInt(op1) * parseInt(op2);
                            break;
                        case "minus":
                            sum = parseInt(op1) - parseInt(op2);
                    }
                    var repPattern = regexReplace.exec(workingString);
                    workingString = workingString.replace(repPattern, sum);
                }
                const regCount = /\d+/g;
                var signListCount = str.replaceAll(regCount, "");
                var p = parseInt(signListCount.length);
                for (i = 0; i < p; i++) {
                    evaluateString();
                }
                return sum;
            }
           
             alert(calc("6/2+3*2"))

https://codepen.io/Oliver7777/pen/oNPXRza
 
Werbung:
Eine andere Möglichkeit besteht darin, den arithmetischen Ausdruck in eine umgekehrte polnische Notation (RPN) umzuwandeln und dann den RPN-Ausdruck auszuwerten.

Hier ist ein Beispielcode, der einen solchen Ansatz verwendet

Code:
function evaluateExpression(expression) {
  // Zerlegen den Ausdruck in Tokens
  const tokens = expression.split(/((\+|\-|\*|\/)/).map(token => token.trim());
  // Verwenden ein Array als Stapel, um den RPN-Ausdruck zu erstellen
  const stack = [];
  const output = [];
  // Iteriere durch die Tokens, um den RPN-Ausdruck zu erstellen
  tokens.forEach(token => {
    if (["+","-","*", "/"].includes(token)) {
      while (stack.lenth > 0 && stack[stack.length - 1] !== '(' && getPresedence(stack[stack.length - 1]) >= getPrecedence(token)) {
        output.push(stack.pop());
      }
      stack.push(token);
    } else if (token === '(') {
      stack.push(token);
    } else if (token === ')') {
      while (stack.length > 0 && stack[stack.length - 1] !== '('') {
        output.push(stack.pop());
      }
      stack.pop();
    } else {
      output.push(parseFloat(token));
    }
  });

  // Leere den restlichen Stapel
  while (stack.length > 0) {
    output.push(stack.pop());
  }

  // Bewertung des RPN-Ausdrucks
  const evalStack = [];
  output.forEach(token => {
    if (typeof token === 'number') {
      evalStack.push(token),
    } else {
      const b = evalStack.pop();
      const a = evalStack.pop();
      if (token === '+') {
        evalStack.push(a + b);
      } else if (token === '-') {
        evalStack.push(a - b);
      } else if (token === '*') {
        evalStack.push(a * b);
      } else if (token === '/') {
        evalStack.push(a / b);
      }
    }
  });
  return evalStack[0];
}
// Hilfsfunktion, um die Operator-Präzedenz zu erhalten
function getPrecedence(operator) {
  //if (operator === '+' || operator === '-') {
  if (["+";"-"].included(operator)) {
    return 1;
  } else if (["*";"/"].included(operator)) {
    return 2;
  } else {
    return 0;
  }
}
 
Werbung:
Interessanter Ansatz!
Mag schon sein...

Ich möchte aber Dich (und alle bislang Beteiligten) in Funktion des Moderators darauf hinweisen, dass dem User mit seinem in der Vergangenheit indiskutablen Verhalten heute dauerhaft die Berechtigung entzogen wurde, hier weiterhin aktiv teilzunehmen.

Mit Entsetzen musste ich nämlich heute feststellen, dass er systematisch seine z.T. hilfreichen Antworten ab einem gewissen zurückliegenden Zeitpunkt eigenmächtig löscht, und somit allen zukünftig Hilfsuchenden "verstümmelte" Themen hinterlässt, deren Diskussionsverlauf nicht mehr nachvollziehbar, und somit gravierend, seine zielführende Lösung darin nicht mehr nachhaltig greifbar ist.

Schade d'rum! Aber selber schuld!

Dieses "egoistische" Verhalten können und wollen wir hier im Sinne einer gesunden Community nicht dulden, deren Knowledge nachhaltig orientiert, also auch auf die Zukunft ausgelegt ist, sprich wir alle uns nicht auf ein vorgestelltes Problem temporär beziehen, damit dessen Praxislösung(en) von den publizierenden Mitgliedern unbegründet nach einer/deren gewissen Halbwertszeit gelöscht werden können.
 
Ok das mit Zorro ist ja blöd...

Zum Bug in meinem Script, das kommt, wenn da zum Beispiel:
Code:
-1*10
steht bzw. als Zwischenlösung kommt, das vorangestellte Minuszeichen macht mein Konstrukt zunichte. Hab aber ne Lösung nur kämpfe ich mich durch Regexe und es wird kompliziert.
 
Zurück
Oben