This code works as a calculator, but the scratch pad at codeacademy tells me that eval is evil. Is there another way to do the same thing without using eval?
var calculate = prompt("Enter problem");
alert(eval(calculate));
This code works as a calculator, but the scratch pad at codeacademy tells me that eval is evil. Is there another way to do the same thing without using eval?
var calculate = prompt("Enter problem");
alert(eval(calculate));
Share
Improve this question
edited Jun 18, 2015 at 19:40
asked Feb 17, 2013 at 0:52
user2079551user2079551
10
- 2 You want to parse an equation from a string into working code? Then you'll need to build a parser. – the system Commented Feb 17, 2013 at 0:57
- 1 And building a parser is no easy task. – Adam Rackis Commented Feb 17, 2013 at 0:59
- 2 @AdamRackis well that's true but something to handle infix arithmetic isn't that bad - it's probably the best "my first parser" project :-) – Pointy Commented Feb 17, 2013 at 1:00
-
1
@VisioN: That's effectively
eval
. – the system Commented Feb 17, 2013 at 1:03 - 3 @VisioN that's like replacing cheddar with mozzarella for a lactose intolerant person :-) – Pointy Commented Feb 17, 2013 at 1:03
4 Answers
Reset to default 5eval
evaluates the string input as JavaScript and coincidentally JavaScript supports calculations and understands 1+1
, which makes it suitable as a calculator.
If you don't want to use eval
, which is good, you have to parse that string yourself and, finally, do the putation yourself (not exactly yourself though). Have a look at this math processor, which does what you want.
Basically what you do is:
- Read the input string char by char (with this kind of problem it's still possible)
- Building a tree of actions you want to do
- At the end of the string, you evaluate the tree and do some calculations
For example you have "1+2/3"
, this could evaluate to the following data structure:
"+"
/ \
"1" "/"
/ \
"2" "3"
You could then traverse that structure from top to bottom and do the putations.
At first you've got the "+"
, which has a 1 on the left side and some expression on the right side,
so you have to evaluate that expression first. So you go to the "/"
node, which has two numeric children. Knowing that, you can now pute 2/3
and replace the whole "/"
node with the result of that. Now you can go up again and pute the result of the "+
" node: 1 + 0.66
. Now you replace that node with the result and all you've got left is the result of the expression.
Some pseudo code on how this might look in your code:
calculation(operator, leftValue, rightValue):
switch operator {
case '+': return leftValue + rightValue
case '-': return 42
}
action(node):
node.value = calculation(node.operator, action(node.left) action(node.right))
As you might have noticed, the tree is designed in such a way that it honors operator precedence. The /
has a lower level than the +
, which means it get's evaluated first.
However you do this in detail, that's basically the way to go.
You can use the expression parser that is included in the math.js library:
http://mathjs
Example usage:
mathjs.evaluate('1.2 / (2.3 + 0.7)'); // 0.4
mathjs.evaluate('5.08 cm in inch'); // 2 inch
mathjs.evaluate('sin(45 deg) ^ 2'); // 0.5
mathjs.evaluate('9 / 3 + 2i'); // 3 + 2i
mathjs.evaluate('det([-1, 2; 3, 1])'); // -7
You can use eval safely for a simple arithmetic calculator by filtering the input- if you only accept digits, decimal points and operators (+,-,*,/) you won't get in much trouble. If you want advanced Math functions, you are better off with the parser suggestions.
function calculate(){
"use strict";
var s= prompt('Enter problem');
if(/[^0-9()*+\/ .-]+/.test(s)) throw Error('bad input...');
try{
var ans= eval(s);
}
catch(er){
alert(er.message);
}
alert(ans);
}
calculate()
I write some functions when I had a problem like this. Maybe this can help:
data = [
{id:1,val1:"test",val2:"test2",val2:"test3"},
{id:2,val1:"test",val2:"test2",val2:"test3"},
{id:3,val1:"test",val2:"test2",val2:"test3"}
];
datakey = Object.keys(data[0]);
// here's a fix for e['datakey[f]'] >> e[x]
vix = function(e,f){
a = "string";
e[a] = datakey[f];
x = e.string;
end = e[x];
delete e.string;
return end;
};
// here's a fix to define that variable
vox = function(e,f,string){
a = "string";
e[a] = datakey[f];
x = e.string;
end = e[x] = string;
delete e.string;
};
row = 2 // 3th row ==> {id:3,val1:"test",val2:"test2",val2:"test3"}
column = 1 //datakey 2 ==> val1
vox(data[row],column,"new value");
alert(data[2].val1); //the value that we have changed