This isn't as short and concise as the other suggested answers, but it may be more understandable, and it uses the builtin tokenize library, so someone else has already solved the problems for you. Here's an example boiled down from the tokenize Python docs
from tokenize import tokenize, ENCODING, ENDMARKER, NEWLINE
from io import BytesIO
def tok_string(exp: str):
token_gen = tokenize(BytesIO(exp.encode("utf-8")).readline)
result = list()
for token in token_gen:
print(token)
if token.type not in (ENCODING, ENDMARKER, NEWLINE):
result.append(token.string)
return result
print("FIRST EXAMPLE")
print(tok_string("2*3 +11+2"))
print("\n SECOND EXAMPLE")
print(tok_string("(2*3)+(4*60)/3"))
generates the output:
FIRST EXAMPLE
TokenInfo(type=62 (ENCODING), string='utf-8', start=(0, 0), end=(0, 0), line='')
TokenInfo(type=2 (NUMBER), string='2', start=(1, 0), end=(1, 1), line='2*3 +11+2')
TokenInfo(type=54 (OP), string='*', start=(1, 1), end=(1, 2), line='2*3 +11+2')
TokenInfo(type=2 (NUMBER), string='3', start=(1, 2), end=(1, 3), line='2*3 +11+2')
TokenInfo(type=54 (OP), string='+', start=(1, 4), end=(1, 5), line='2*3 +11+2')
TokenInfo(type=2 (NUMBER), string='11', start=(1, 5), end=(1, 7), line='2*3 +11+2')
TokenInfo(type=54 (OP), string='+', start=(1, 7), end=(1, 8), line='2*3 +11+2')
TokenInfo(type=2 (NUMBER), string='2', start=(1, 8), end=(1, 9), line='2*3 +11+2')
TokenInfo(type=4 (NEWLINE), string='', start=(1, 9), end=(1, 10), line='')
TokenInfo(type=0 (ENDMARKER), string='', start=(2, 0), end=(2, 0), line='')
['2', '*', '3', '+', '11', '+', '2']
SECOND EXAMPLE
TokenInfo(type=62 (ENCODING), string='utf-8', start=(0, 0), end=(0, 0), line='')
TokenInfo(type=54 (OP), string='(', start=(1, 0), end=(1, 1), line='(2*3)+(4*60)/3')
TokenInfo(type=2 (NUMBER), string='2', start=(1, 1), end=(1, 2), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string='*', start=(1, 2), end=(1, 3), line='(2*3)+(4*60)/3')
TokenInfo(type=2 (NUMBER), string='3', start=(1, 3), end=(1, 4), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string=')', start=(1, 4), end=(1, 5), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string='+', start=(1, 5), end=(1, 6), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string='(', start=(1, 6), end=(1, 7), line='(2*3)+(4*60)/3')
TokenInfo(type=2 (NUMBER), string='4', start=(1, 7), end=(1, 8), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string='*', start=(1, 8), end=(1, 9), line='(2*3)+(4*60)/3')
TokenInfo(type=2 (NUMBER), string='60', start=(1, 9), end=(1, 11), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string=')', start=(1, 11), end=(1, 12), line='(2*3)+(4*60)/3')
TokenInfo(type=54 (OP), string='/', start=(1, 12), end=(1, 13), line='(2*3)+(4*60)/3')
TokenInfo(type=2 (NUMBER), string='3', start=(1, 13), end=(1, 14), line='(2*3)+(4*60)/3')
TokenInfo(type=4 (NEWLINE), string='', start=(1, 14), end=(1, 15), line='')
TokenInfo(type=0 (ENDMARKER), string='', start=(2, 0), end=(2, 0), line='')
['(', '2', '*', '3', ')', '+', '(', '4', '*', '60', ')', '/', '3']
As you can see, there's a lot more information provided by the tokenize-er that you may want to take advantage of.