65

Let's say I have a standard Python string (such as one obtained from raw_input()), maybe "2 + 2" for simplicity's sake.

I'd like to convert this string to standard math operations in Python, such that "2 + 2" would return 4.

Is there an easy way to do this, or would I have to split on the spaces and parse each number/symbol manually, then do the math based on what I find?

Do I want Regex?

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Elliot Bonneville
  • 51,872
  • 23
  • 96
  • 123
  • Is this homework? I think you'll basically have to write a parser. You could use some iterative or recursive regex to handle parens and order of operations, then just straight parse and linearly process everything else. – Silas Ray Mar 13 '12 at 14:29
  • Ha, I figured somebody was going to ask that. Yes, it is involved in homework, but it's not what you think. You see, I'm writing a geometry/trig calculator to make my math-life easier. (See here: http://stackoverflow.com/questions/9624515/basic-trig-math-atan-issue) I figure that if I understand a problem well enough to write a program that can figure it out, I don't need to do the work manually. :) – Elliot Bonneville Mar 13 '12 at 14:31
  • 2
    Also consider SimPy for symbolic math. – Benjamin Mar 13 '12 at 14:37
  • This has been [asked before](http://stackoverflow.com/q/1545403/589206) – hochl Mar 13 '12 at 14:39
  • Well, if you can control the usage, a realtime input parser might work better for you. Then you won't be stuck having to do so much post-processing of the string. What I'm getting at is a system that actually builds some sort of computational object as you type, then upon entering 'execute' or something, it runs the object and returns a result. – Silas Ray Mar 13 '12 at 14:39

8 Answers8

103

Warning: this way is not a safe way, but is very easy to use. Use it wisely.

Use the eval function.

print eval('2 + 4')

Output:

6

You can even use variables or regular python code.

a = 5
print eval('a + 4')

Output:

9

You also can get return values:

d = eval('4 + 5')
print d

Output:

9

Or call functions:

def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

a = 20
b = 10    
print eval('add(a, b)')
print eval('subtract(a, b)')

Output:

30
10

In case you want to write a parser, maybe instead you can built a python code generator if that is easier and use eval to run the code. With eval you can execute any Python evalution.

Why eval is unsafe?

Since you can put literally anything in the eval, e.g. if the input argument is:

os.system(‘rm -rf /’)

It will remove all files on your system (at least on Linux/Unix). So only use eval when you trust the input.

Michel Keijzers
  • 15,025
  • 28
  • 93
  • 119
13

You could use this function which is doing the same as the eval() function, but in a simple manner, using a function.

def numeric(equation):
    if '+' in equation:
        y = equation.split('+')
        x = int(y[0])+int(y[1])
    elif '-' in equation:
        y = equation.split('-')
        x = int(y[0])-int(y[1])
    return x
MOHAMMAD WASEEM
  • 185
  • 1
  • 6
10

Regex won't help much. First of all, you will want to take into account the operators precedence, and second, you need to work with parentheses which is impossible with regex.

Depending on what exactly kind of expression you need to parse, you may try either Python AST or (more likely) pyparsing. But, first of all, I'd recommend to read something about syntax analysis in general and the Shunting yard algorithm in particular.

And fight the temptation of using eval, that's not safe.

bereal
  • 32,519
  • 6
  • 58
  • 104
  • I think `eval()` would be okay in my case, since I'm the only one that would ever be using the program. (at least, that's what it looks like right now. :) I don't think I'll need to cover all the security options. – Elliot Bonneville Mar 13 '12 at 14:33
  • Reading about syntax analysis and building your own parser might be overkill just to solve his problem. – hochl Mar 13 '12 at 14:36
  • 1
    If your goal is to, "know the math well enough to justify not doing it out by hand," using `eval()` to do it all automagically for you is not exactly going to meet your goals. – Silas Ray Mar 13 '12 at 14:37
  • 1
    Objection! Reading about syntax analysis is never overkill! – bereal Mar 13 '12 at 14:38
  • Well, I already know the math. I just want to automate some of the more basic stuff. I can't see eval() covering quadratic formula or 3D graphing formulas. :) – Elliot Bonneville Mar 13 '12 at 14:40
  • Well it surely won't hurt him either ^^ – hochl Mar 13 '12 at 14:40
8

The easiest way is to use eval as in:

 >>> eval("2   +    2")
 4

Pay attention to the fact I included spaces in the string. eval will execute a string as if it was a Python code, so if you want the input to be in a syntax other than Python, you should parse the string yourself and calculate, for example eval("2x7") would not give you 14 because Python uses * for multiplication operator rather than x.

zenpoy
  • 19,490
  • 9
  • 60
  • 87
6

If you want to do it safely, you may want to use http://docs.python.org/library/ast.html#ast.literal_eval

from this answer: Python "safe" eval (string to bool/int/float/None/string)

It might not do math, but you could parse the math operators and then operate on safely evaluated terms.

Community
  • 1
  • 1
Garrett Berg
  • 2,585
  • 1
  • 22
  • 21
4

A simple way but dangerous way to do this would be to use eval(). eval() executes the string passed to it as code. The dangerous thing about this is that if this string is gained from user input, they could maliciously execute code that could break the computer. I would get the input, check it with a regex, and then execute it if you determine if it's OK. If it's only going to be in the format "number operation number", then you could use a simple regex:

import re
s = raw_input('What is your math problem? ')
if re.findall('\d+? *?\+ *?\d+?', s):
  print eval(s)
else:
  print "Try entering a math problem"

Otherwise, you would have to come up with something a bit stricter than this. You could also do it conversely, using a regex to find if certain things are not in it, such as numbers and operations. Also you could check to see if the input contains certain commands.

CoffeeRain
  • 4,460
  • 4
  • 31
  • 50
4

The asker commented:

I figure that if I understand a problem well enough to write a program that can figure it out, I don't need to do the work manually.

If he's writing a math expression solver as a learning exercise, using eval() isn't going to help. Plus it's terrible design.

You might consider making a calculator using Reverse Polish Notation instead of standard math notation. It simplifies the parsing considerably. It would still be a good exercise

japreiss
  • 11,111
  • 2
  • 40
  • 77
  • 1
    Thing is, it's not a learning exercise. It's an, ah, redundant-work-eliminator. And the work that I'd like to eliminate is only redundant because I already know it. ;) – Elliot Bonneville Mar 13 '12 at 19:45
  • But calling `eval(expression)` doesn't mean that you "understand the problem well enough to write a program". It means that Python's input parser understands the problem. – japreiss Mar 13 '12 at 19:52
  • Well, I'm a bit beyond standard equations, multiplication, and division. Python's input parser wouldn't understand the problems I'm working on now. Indeed, there's no way to even input them into a standard console. :) – Elliot Bonneville Mar 13 '12 at 19:55
  • 1
    @ElliotBonneville You might want to look into the math library also. – CoffeeRain Mar 13 '12 at 19:58
  • I'll take a peek at it, thanks. – Elliot Bonneville Mar 13 '12 at 19:59
2

The best way would be to do:

print eval("2 + 2")

If you wanted to you could use a variable:

addition = eval("2 + 2") print addition

If you really wanted to, you could use a function:

def add(num1, num2): eval("num1 + num2")

typemaster
  • 31
  • 1
  • 4