Domanda

I have a task where I need to convert equations in one language (MATLAB) to another (C++) using Python. Everything is straightforward except the power operation. The equations are represented by Python strings.

For example, I want to convert

Eq = ((a+b)^2 + (c+d)^(1/2)) * e

to,

Eq = (pow((a+b),2) + pow(c+d, 1/2)) * e

I tried regular expression, but it does not seem to work because of nested parenthesis. Is there any good way to do this?

È stato utile?

Soluzione

The best way to solve this would be to use Abstract Syntax Tree of Python. We can get that using ast module.

import ast, _ast

ops = {_ast.Mult: "*", _ast.Add: "+", _ast.BitXor: "pow", _ast.Div: "/"}

def rec(n):
    if isinstance(n, _ast.Expr):
        return rec(n.value)
    elif isinstance(n, _ast.BinOp):
        if isinstance(n.op, _ast.BitXor):
            return "{}({}, {})".format(ops[type(n.op)], rec(n.left),rec(n.right))
        else:
            return "({} {} {})".format(rec(n.left), ops[type(n.op)],rec(n.right))
    elif isinstance(n, _ast.Name):
        return n.id
    elif isinstance(n, _ast.Num):
        return n.n

print rec(ast.parse("(((a+b)^2) + ((c+d)^(1/2))) * e").body[0])
# ((pow((a + b), 2) + pow((c + d), (1 / 2))) * e)

Note: Since ^ means Binary XOR operation in Python, you need to enclose that expression with an extra parenthesis, like I have shown in the example.

First, we check if it is an expression, then we process its value. If it is a binary operation, we check of it is Bitwise XOR, in that case we return the result in a different format, otherwise we return the result like left op right. If the current item looks like a name, then we return its id or if it is a number we return the attribute n.

Altri suggerimenti

You can do it as follows. Note: This is still a very primitive approach and I'd be careful about relying on it 100%:

import re

s = "Eq = ((a+b)^2 + (c+d)^(1/2)) * e"

>>> print re.sub(r'\(([^()\s]*)\)\^\(?([^()\s]*)\)?', 'pow(\\1,\\2)', s)
Eq = (pow(a+b,2) + pow(c+d,1/2)) * e

I think I'd do this with a simple tokeniser and parser rather than regular expressions. It's not that hard to write and will be more robust and readable than a regular expression based parser.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top