Skip to content

Instantly share code, notes, and snippets.

@ohaz
Created March 8, 2016 09:07
Show Gist options
  • Save ohaz/ed0b14a487b0569aad2d to your computer and use it in GitHub Desktop.
Save ohaz/ed0b14a487b0569aad2d to your computer and use it in GitHub Desktop.
Parse math formulas in python and put parentheses around Mult/Div
from __future__ import print_function
import ast
def recurse(node):
if isinstance(node, ast.BinOp):
if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
print('(', end='')
recurse(node.left)
recurse(node.op)
recurse(node.right)
if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
print(')', end='')
elif isinstance(node, ast.Add):
print('+', end='')
elif isinstance(node, ast.Sub):
print('-', end='')
elif isinstance(node, ast.Mult):
print('*', end='')
elif isinstance(node, ast.Div):
print('/', end='')
elif isinstance(node, ast.Num):
print(node.n, end='')
else:
for child in ast.iter_child_nodes(node):
recurse(child)
def search_expr(node):
returns = []
for child in ast.iter_child_nodes(node):
if isinstance(child, ast.Expr):
return child
returns.append(search_expr(child))
for ret in returns:
if isinstance(ret, ast.Expr):
return ret
return None
formula = '3+7*8/2'
a = ast.parse(formula)
expr = search_expr(a)
if expr is not None:
recurse(expr)
@bigtoerag
Copy link

This is exactly what I am after but I cant get it to run in my Flask app, it always returns None. Have you tried to use it with the formula as an input variable and the parsing returning the formatted formula or None?

def fix(formula):
    def recurse(node):
        if isinstance(node, ast.BinOp):
            if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
                print('(', end='')
            recurse(node.left)
            recurse(node.op)
            recurse(node.right)
            if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
                print(')', end='')
        elif isinstance(node, ast.Add):
            print('+', end='')
        elif isinstance(node, ast.Sub):
            print('-', end='')
        elif isinstance(node, ast.Mult):
            print('*', end='')
        elif isinstance(node, ast.Div):
            print('/', end='')
        elif isinstance(node, ast.Num):
            print(node.n, end='')
        else:
            for child in ast.iter_child_nodes(node):
                recurse(child)
    
    
    def search_expr(node):
        returns = []
        for child in ast.iter_child_nodes(node):
            if isinstance(child, ast.Expr):
                return child
            returns.append(search_expr(child))
        for ret in returns:
            if isinstance(ret, ast.Expr):
                return ret
        return None
    a = ast.parse(formula)
    expr = search_expr(a)
    output = recurse(expr)
    return output

@ohaz
Copy link
Author

ohaz commented Apr 29, 2020

The issue is that this gist is printing the results, not putting them in a variable. That's why it returns None

@bigtoerag
Copy link

Would it be easy/possible to switch it over to variable? I could try but I am greener than grass at this.

@ohaz
Copy link
Author

ohaz commented Apr 29, 2020

yep like this:

from __future__ import print_function
import ast

def fix(formula):
    def recurse(node):
        result = ''
        if isinstance(node, ast.BinOp):
            if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
                result += '('
            result += recurse(node.left)
            result += recurse(node.op)
            result += recurse(node.right)
            if isinstance(node.op, ast.Mult) or isinstance(node.op, ast.Div):
                result += ')'
        elif isinstance(node, ast.Add):
            result += '+'
        elif isinstance(node, ast.Sub):
            result += '-'
        elif isinstance(node, ast.Mult):
            result += '*'
        elif isinstance(node, ast.Div):
            result += '/'
        elif isinstance(node, ast.Num):
            result += str(node.n)
        else:
            for child in ast.iter_child_nodes(node):
                result += recurse(child)
        return result
    
    
    def search_expr(node):
        returns = []
        for child in ast.iter_child_nodes(node):
            if isinstance(child, ast.Expr):
                return child
            returns.append(search_expr(child))
        for ret in returns:
            if isinstance(ret, ast.Expr):
                return ret
        return None
    a = ast.parse(formula)
    expr = search_expr(a)
    output = recurse(expr)
    return output

@bigtoerag
Copy link

bigtoerag commented Apr 30, 2020

Legend Thankyou, just tested perfectly. I will trawl over it and see if I can learn more about it and not have to ask next time.
All part of my new COVID skills in python
Dice roller

@ohaz
Copy link
Author

ohaz commented Apr 30, 2020

Looking good! So nice to see that there are good things coming out of COVID :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment