首页 文章

如何从字符串中绘制数学函数?

提问于
浏览
-3

我有一个表示函数的字符串,如 "x * (x - 32 ( 2 /x) )" . 我正在使用 matplotlib ,但我不知道如何将此字符串转换为要绘制的点数组 .

1 回答

  • 7

    您可以使用pythons eval function, but this is dangerous and generally considered bad style 将字符串转换为代码,请参阅:https://stackoverflow.com/a/661128/3838691 . 如果用户可以输入字符串,他们可以输入类似 import subprocess; subprocess.check_call(['rm', '-rf', '*'], shell=True) 的内容 .

    因此,请确保为此构建合理的安全性 .

    您可以定义一个接受字符串并返回函数的函数 . 我们需要做一些预处理,以允许用户输入更像他习惯的公式(^等):

    编辑:第二个版本 - 白名单而不是黑名单

    定义允许和支持的单词似乎比将某些单词列入黑名单更好:

    import re
    
    replacements = {
        'sin' : 'np.sin',
        'cos' : 'np.cos',
        'exp': 'np.exp',
        'sqrt': 'np.sqrt',
        '^': '**',
    }
    
    allowed_words = [
        'x',
        'sin',
        'cos',
        'sqrt',
        'exp',
    ]
    
    def string2func(string):
        ''' evaluates the string and returns a function of x '''
        # find all words and check if all are allowed:
        for word in re.findall('[a-zA-Z_]+', string):
            if word not in allowed_words:
                raise ValueError(
                    '"{}" is forbidden to use in math expression'.format(word)
                )
    
        for old, new in replacements.items():
            string = string.replace(old, new)
    
        def func(x):
            return eval(string)
    
        return func
    
    
    if __name__ == '__main__':
    
        func = string2func(input('enter function: f(x) = '))
        a = float(input('enter lower limit: '))
        b = float(input('enter upper limit: '))
        x = np.linspace(a, b, 250)
    
        plt.plot(x, func(x))
        plt.xlim(a, b)
        plt.show()
    

    结果:

    $ python test.py
    enter function: f(x) = x^2
    enter lower limit: 0
    enter upper limit: 2
    

    enter image description here

    对于恶意用户:

    enter function: f(x) = import subprocess; subprocess.check_call(['rm', '-rf', '*'], shell=True)
    Traceback (most recent call last):
      File "test.py", line 35, in <module>
        func = string2func(input('enter function: f(x) = '))
      File "test.py", line 22, in string2func
        '"{}" is forbidden to use in math expression'.format(word)
    ValueError: "import" is forbidden to use in math expression
    

    编辑:第一版 - 黑名单危险词:

    import numpy as np
    import matplotlib.pyplot as plt
    
    # there should be a better way using regex
    replacements = {
        'sin' : 'np.sin',
        'cos' : 'np.cos',
        'exp': 'np.exp',
        '^': '**',
    }
    
    # think of more security hazards here
    forbidden_words = [
        'import',
        'shutil',
        'sys',
        'subprocess',
    ]
    
    def string2func(string):
        ''' evaluates the string and returns a function of x '''
        for word in forbidden_words:
            if word in string:
                raise ValueError(
                    '"{}" is forbidden to use in math expression'.format(word)
                )
    
        for old, new in replacements.items():
            string = string.replace(old, new)
    
        def func(x):
            return eval(string)
    
        return func
    

相关问题