3

I am trying to create a simple online calculator that can run basic calculations in JavaScript.

I have managed to create the interface so that numbers and operators and stored in a form field.

What I would like to be able to do is pass the values within the form field to a function that will calculate the total of the form field.

The form field could contain anything from a simple "10 + 10" to more complex equations using brackets. The operators in use are +, -, *, and /.

Is it possible to pass the form field's text (a string) to a JavaScript function that can recognize the operators and the perform the function of the operation on the values?

A possible value in the text field would be:

120/4+130/5

The function should then return 56 as the answer. I have done this in JavaScript when I know the values like this:

function WorkThisOut(a,b,c,d) {

var total = a/b+c/d;

alert (total);
}

WorkThisOut(120,4,130,5);

What I would like to be able to do is pass the full value "120/4+130/5" to the function and it be able to extract the numbers and operators to create the total.

Does anyone have any ideas on how this could be done or if it is even possible? this may get more complex where I may need to pass values in parentheses "(120/4)+(130/5)"

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
jdublu
  • 187
  • 1
  • 4
  • 9
  • 7
    Whatever you do, stay the hell away from `eval` – Aren Jun 01 '12 at 21:44
  • 2
    @Aren Why? There are a lot of issues with `eval`, but as long as the input is secure, there's no doubt it's the fastest formula parser for Javascript developers. I don't see the point in pretending it doesn't even exist. – MaxArt Jun 01 '12 at 21:52
  • You can use `eval`, as long as you run it from an iframe in a domain that's only meant for that purpose and can't access your own domain. – Ruan Mendes Jun 01 '12 at 21:54
  • His input is a text input, he is going to have to validate the input, that means he is pretty much doing all the work of parsing the input into computable components anyway, why not just save the security risk and glue the pieces together? `eval` is great if you can trust the input, but can he trust his input? – Aren Jun 01 '12 at 22:06
  • @Aren You can pass the input to be run inside an iframe in a different domain. – Ruan Mendes Jun 01 '12 at 22:12
  • @Juan Mendes that is far too much just so you can use eval. you can use split and regexp and achieve this without having to do any of that labor whatsoever. – Ohgodwhy Jun 01 '12 at 22:55
  • @Ohgodwhy I know that, did you see my answer? – Ruan Mendes Jun 02 '12 at 00:15
  • @Ohgodwhy it's the standard solution nowadays if you need to allow the user to run a script. May not be for everyone, but it's completely safe – Ruan Mendes Jun 02 '12 at 00:33
  • Does this answer your question? [Are Variable Operators Possible?](https://stackoverflow.com/questions/5834318/are-variable-operators-possible) – Liam May 25 '21 at 13:57

5 Answers5

8

I may get blasted for this. But, here it goes anyway.

There are three solutions I can think of for this:

  1. Implement your own parser, lexer and parse out the code. That's not super easy, but it may be a great learning experience.
  2. Run an eval under a subdomain meant only for that, so that scripts can't maliciously access your site
  3. Sanitize the input to contain only 12345678790+-/*().

 eval(input.replace(/[^0-9\(\)\+\-\*\/\.]/g, ""));

Please blast away with tricks to get around this solution

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Will never be safe. `rm -rf /dir/allyour.files` – Ohgodwhy Jun 01 '12 at 22:15
  • 4
    @Ohgodwhy I'll gladly take the downvote if you give me an input string for which it fails, your comment looks like a troll. – Ruan Mendes Jun 01 '12 at 22:19
  • your answer is invalid, because he needs a `-` operator, and you filter it: moreover, you can still use the same code to get around your eval. – Ohgodwhy Jun 02 '12 at 00:19
  • 3
    @Ohgodwhy Try it before you start talking nonsense `eval("2-2".replace(/[^0-9\(\)\+\-\*\/\.]/g, "")) === 0 // true` I don't filter it out, I keep it in the whitelist, look at the regexp; accepts numbers, operators and parentheses – Ruan Mendes Jun 02 '12 at 00:22
6

You can use the expression parser included with the math.js library:

http://mathjs.org

Example usage:

math.eval('1.2 / (2.3 + 0.7)');   // 0.4
math.eval('5.08 cm in inch');     // 2 inch
math.eval('sin(45 deg) ^ 2');     // 0.5
math.eval('9 / 3 + 2i');          // 3 + 2i
math.eval('det([-1, 2; 3, 1])');  // -7
Jos de Jong
  • 6,602
  • 3
  • 38
  • 58
3

It is pretty hard to do much damage with eval if you don't allow identifiers.

function reval(string){
    var answer='';
    if(/^[\d()\/*.+-]+$/.test(str)){
        try{
            answer= eval(str);
        }
        catch(er){
            answer= er.name+', '+er.message;
        }

    }
    return answer;
}
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • *"...if you don't allow identifiers."* Or `"`, `'`, `[`, and `]` (which you also disallow above). `[][0]+""` gets me the characters `u`, `n`, `d`, `e`, `f`, `i`, and `n` to work with. Someone cleverer than me could probably use that and similar tricks to bootstrap...something. But as the OP's talking about doing this immediately with input from the current user, it doesn't really matter; they could always open the console and do what they want anyway... :-) – T.J. Crowder Feb 25 '20 at 09:26
2

what about eval?

consider calc as the id of textfield. then

$('#calc').change(function(e){                
    alert(eval($(this).val()));
})

but remember to validate input before processing.

osdamv
  • 3,493
  • 2
  • 21
  • 33
Sarowar
  • 452
  • 4
  • 14
  • 3
    Eval is a poor choice for this, it allows for exploitations and leaks that allow for you to be injected quite easily. By providing this option and not the information on how to secure it, you've just set a man up for failure. – Ohgodwhy Jun 01 '12 at 22:16
  • 3
    @Ohgodwhy AFAIK in chrome or ff you can inject js, directly from the console, if the user want to inject js he will do it anyway – osdamv Jun 01 '12 at 22:37
  • 1
    @osdamv The problem is not the user on the website injecting code. The problem is a user getting that code to run under somebody else's privileges – Ruan Mendes Jun 02 '12 at 00:13
  • 5
    @Juan Mendes could you explain me how to do that in javascript browser sand box? – osdamv Jun 04 '12 at 18:21
1

This is a pretty old topic, but for the new visitors who have similar problem: the string-math package calculates the [String] equations like in the sample above 120/4+130/5. It also recognizes parentheses.

Paweł
  • 4,238
  • 4
  • 21
  • 40