0

How would you parse a list in python to combine integer while leaving the operator of an equation alone?

list =['(' ,'1', '+', '2', ')', '+', '(', '2', '0'. '0', '/', '2', '5', ')']

I would like to ultimately be able to use a list like this to create a calculable equation taken from user input. Is it possible?

trotta
  • 1,232
  • 1
  • 16
  • 23
  • 1
    Have a look at the [Shunting Yard Algorithm](https://en.m.wikipedia.org/wiki/Shunting-yard_algorithm). Yes, it is possible. – hnefatl Aug 04 '17 at 07:15
  • Possible duplicate of [Smart design of a math parser?](https://stackoverflow.com/questions/114586/smart-design-of-a-math-parser) – hnefatl Aug 04 '17 at 07:18
  • You neither say what is the exact output and the expected input, you give no context on what you are trying to achieve. I'm sorry but this is *unclear*. – Serge Ballesta Aug 04 '17 at 07:18

3 Answers3

2

If the object is to do the calculation, skip converting to integers entirely and do an eval. Suppose you have this string from input '(1+2)+(200/25)', you can do:

calc_result = eval(calc_input) # equals 11

However be careful, the use of eval can run any python code that is given to it, so if it's a program for public use someone will figure out a way to use this part to insert code you never intended to allow.

eval and exec should generally be avoided because they can be a security risk. For details, please see Eval really is dangerous by SO veteran Ned Batchelder (thanks to @PM2Ring for the comment)

Ofer Sadan
  • 11,391
  • 5
  • 38
  • 62
  • 4
    Please do not advice to use the *evil `eval`* when `ast.literal_eval` can do the job. – Serge Ballesta Aug 04 '17 at 07:16
  • 1
    That's like giving a user way to inject SQL! – Ubdus Samad Aug 04 '17 at 07:17
  • 1
    @SergeBallesta How would you use `ast.literal_eval` to evaluate `'(1+2)+(200/25)'`? It can evaluate expressions containing `+` and `-`, as a side-benefit of its ability to evaluate complex numbers, and it can even handle parenthesised expressions, but it doesn't do multiplication or division. – PM 2Ring Aug 04 '17 at 07:22
  • 1
    For `ast.literal_eval` see also [this question](https://stackoverflow.com/q/20748202/216074) which covers the expression evaluation property of it, how it’s just a side effect of the necessary parsing behavior, and how to *safely* evaluate simple expressions instead. – poke Aug 04 '17 at 08:07
1

if you do not mind using sympy:

from sympy import sympify

lst = ['(', '1', '+', '2', ')', '+', '(', '2', '0', '0', '/', '2', '5', ')']

res = sympify(''.join(lst))
print(res)  # 11

(not sure what you mean by leaving the operator of an equation alone. your expression is not an equation...).

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
1

To do this sort of thing properly, you will need a parser. You can create your own: parsing algorithms are well-documented. However, you don't need to build a parser from scratch, you can use a package like pyparsing to create a parser.

If you can guarantee that your user input is totally safe, then you can get Python to evaluate it for you via the built-in eval function. However, eval is slow, and it is a security hole because it can be used to execute arbitrary code, as mentioned in the article by Ned Batchelder that's linked in Ofer Sadan's answer.

But to answer your immediate question, we can easily grab the digits from that list of strings, join them together, and convert the resulting number strings into integers. Grouping the digits and separating them from the non-digits is easily done using itertools.groupby. You just need to give it a function it can use to identify the groups; we can use str.isdigit for that. Here's a short demo:

from itertools import groupby

lst = ['(' ,'1', '+', '2', ')', '+', '(', '2', '0', '0', '/', '2', '5', ')']
a = [int(''.join(g)) if k else next(g) for k, g in groupby(lst, str.isdigit)]
print(a)

output

['(', 1, '+', 2, ')', 200, '/', 25, ')']

If you also want to handle + and - signs and decimal points, it's not too hard to write a function that does that. Proper handling of all floating-point numbers is a little trickier, and it's possibly better to use a parser that already knows how to do that. ;)

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182