Michael
Michael

Reputation: 4351

Convert a string equation to an integer answer

If I have a string

equation = "1+2+3+4"

How do I change it into an int and equate the answer? I was thinking something like this but it would give an error.

answer = (int)equation
print(answer)

The equation could contain +-*/

Upvotes: 7

Views: 15040

Answers (4)

Aaron Hall
Aaron Hall

Reputation: 394975

If we wanted to expose a calculator to the world, I'd be very interested to see if a cracker could work around this:

import string

def less_dangerous_eval(equation):
    if not set(equation).intersection(string.ascii_letters + '{}[]_;\n'):
        return eval(equation)
    else:
        print("illegal character")
        return None

less_dangerous_eval('1*2/3^4+(5-6)')

returns:

3

I know that this can be broken by giving it bad syntax (fixable with a try/except block) or an operation that would take up all of the memory in the system (try/except catching this might be more iffy), but I am not currently aware of any way for someone to gain control.

Upvotes: 5

rlms
rlms

Reputation: 11060

I suggest you use eval and check the input:

def evaluate(s):
    import string
    for i in s:
        if i not in "+-*/ " + string.digits:
            return False       # input is not valid
    return eval(s)

As already mentioned, eval is unsafe, and very difficult to make safe. I remember seeing a very good blog post explaining this, does anyone know what it was? However ast.literal_eval is safe, it doesn't allow __import__ etc. I would strongly recomment using ast.literal_eval instead of eval whenever possible. Unfortunately, in this case it isn't possible. However, in a different case, e.g. one where you only need to support addition and multiplication, you could (and should) use literal_eval instead.

On the other hand, if this is homework with the intention for you to learn about parsing, then I would suggest doing this a different way. I know that if I was a teacher, I would respond to an answer using eval with "Very clever, but this won't help you pass a test on abstract syntax trees." (which are incidentally one thing that you should look at if you want to implement this "properly").

Upvotes: -2

David Heffernan
David Heffernan

Reputation: 612954

If you are prepared to accept the risks, namely that you may be letting hostile users run whatever they like on your machine, you could use eval():

>>> equation = "1+2+3+4"
>>> eval(equation)
10

If your code will only ever accept input that you control, then this is the quickest and simplest solution. If you need to allow general input from users other than you, then you'd need to look for a more restrictive expression evaluator.

Update

Thanks to @roippi for pulling me up and pointing out that the code above executes in the environment of the calling code. So the expression would be evaluated with local and global variables available. Suppress that like so:

eval(equation, {'__builtins__': None})

This doesn't make the use of eval() secure. It just gives it a clean, empty environment in which to operate. A hostile user could still hose your system.

Upvotes: 10

Aaron Hall
Aaron Hall

Reputation: 394975

This works if you only have digits and plusses:

answer = sum(float(i) for i in equation.split('+'))

or if you know they will only be integers

answer = sum(int(i) for i in equation.split('+'))

If you want to be able to evaluate more than that, I suggest you do your homework:

  • Look up the string module (which has string.digits)

  • the math module, which has your operations

  • create logic to perform the operations in proper order

Good luck!

Upvotes: 1

Related Questions