将一串数学函数转换为一个函数

时间:2019-04-05 02:12:24

标签: python

我希望有一个函数,该函数接受一个函数字符串,例如'x**2+x''log(x)',并将一个数字作为x,并返回一个数字。 例如:

translate(2, "x**2") return 4
translate(10, "x**2") return 100

这是我尝试过的。但是,我只能处理x的一位数字。

def translate(x, function):
        func = function.replace('x', str(x))
        res = 0
        i = 0
        while i in range(len(function)):
            if func[i] == '*':
                if func[i+1] == '*':
                    res = res**int(func[i+2])
                    i+=3
                else:
                    res *= int(func[i+1])
                    i+=2
            elif func[i] == '+':
                res += int(func[i+1])
                i+=2
            elif func[i] == '-':
                res -= int(func[i+1])
                i+=2
            elif func[i] == 'l':
                res += math.log(int(func[i+3]))
                i+=4
            else:
                res += int(func[i])
                i+=1

        return res

编辑:我只需要一个简单的翻译函数,因为我没有传递疯狂的复杂函数。

1 个答案:

答案 0 :(得分:1)

编辑: 似乎有很多关于eval()使用不安全的争论,应该在有人使用它之前提及 看到这个线程: Why is using 'eval' a bad practice?

使用内置方法eval()

def translate(x, function):
        return eval(function)

result = translate(10, "x**2")

print(result)

输出:100

Edit2 :另一种无需评估的方法

def translate(s):
    symbols = ['+', '-', '*', '/']
    buff = ''
    num = []
    operations = []

    for i, c in enumerate(s):
        if c in symbols:  # check for operators
            # check for double operators like **
            if s[i + 1] in symbols:  # i.e. checking the first '*' in '**'
                operations.append(2 * c)
                continue
            elif s[i - 1] in symbols:  # i.e. checking the second '*' in '**'
                num.append(float(buff))
                buff = ''
                continue

            operations.append(c)
            num.append(float(buff))
            buff = ''
            continue

        else:
            buff += c
    num.append(float(buff))

    print('input string:', s)
    print('numbers:', num)
    print('operations', operations)

    # "power calculations" to be done first
    for i, x in enumerate(operations):
        if x == '**':
            num[i] = perform[operations[i]](num[i], num[i + 1])
            num.pop(i + 1)
            operations.pop(i)
    # multiply/division
    for i, x in enumerate(operations):
        if x in ['*', '/']:
            num[i] = perform[operations[i]](num[i], num[i + 1])
            num.pop(i + 1)
            operations.pop(i)
    # last addition/subtraction
    for i, op in enumerate(operations):
        if op == '-':
            num[i + 1] = -num[i + 1]

    return sum(num)


# define all operations you need, no need to add + or -
perform = {'*': lambda x, y: x * y, '/': lambda x, y: x / y, '**': lambda x, y: x ** y }

result = translate('5+3+10**2+210-30/2')
print('result =', result)

输出:

input string: 5+3+10**2+210-30/2
numbers: [5.0, 3.0, 10.0, 2.0, 210.0, 30.0, 2.0]
operations ['+', '+', '**', '+', '-', '/']
result = 303.0

Edit3: 较短的正则表达式

import re

def translate(s):
    num = re.findall(r'\d+', s)  # '\d' means digits only
    operations = re.findall(r'\D+', s)  # '\D' means anything but digits

    print('input string:', s)
    print('numbers:', num)
    print('operations', operations)

    # "power calculations" to be done first
    for i, x in enumerate(operations):
        if x == '**':
            num[i] = perform[operations[i]](num[i], num[i + 1])
            num.pop(i + 1)
            operations.pop(i)
    # multiply/division
    for i, x in enumerate(operations):
        if x in ['*', '/']:
            num[i] = perform[operations[i]](num[i], num[i + 1])
            num.pop(i + 1)
            operations.pop(i)
    # last addition/subtraction
    for i, op in enumerate(operations):
        if op == '-':
            num[i + 1] = -num[i + 1]

    return sum(num)


# define all operations you need, no need to add + or -
perform = {'*': lambda x, y: x * y, '/': lambda x, y: x / y, '**': lambda x, y: x ** y }

result = translate('5+3+10**2+210-30/2')
print('result =', result)