计算字符串中的数学表达式

2023-12-07

stringExp = "2^4"
intVal = int(stringExp)      # Expected value: 16

这将返回以下错误:

Traceback (most recent call last):  
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int()
with base 10: '2^4'

我知道eval可以解决这个问题,但是是否有更好且更重要的是更安全的方法来评估存储在字符串中的数学表达式?


eval is evil

eval("__import__('os').remove('important file')") # arbitrary commands
eval("9**9**9**9**9**9**9**9", {'__builtins__': None}) # CPU, memory

注意:即使你使用 set__builtins__ to None使用内省仍然有可能突破:

eval('(1).__class__.__bases__[0].__subclasses__()', {'__builtins__': None})

使用计算算术表达式ast

import ast
import operator as op

# supported operators
operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,
             ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor,
             ast.USub: op.neg}

def eval_expr(expr):
    """
    >>> eval_expr('2^6')
    4
    >>> eval_expr('2**6')
    64
    >>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')
    -5.0
    """
    return eval_(ast.parse(expr, mode='eval').body)

def eval_(node):
    if isinstance(node, ast.Num): # <number>
        return node.n
    elif isinstance(node, ast.BinOp): # <left> <operator> <right>
        return operators[type(node.op)](eval_(node.left), eval_(node.right))
    elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1
        return operators[type(node.op)](eval_(node.operand))
    else:
        raise TypeError(node)

您可以轻松限制每个操作或任何中间结果的允许范围,例如限制输入参数a**b:

def power(a, b):
    if any(abs(n) > 100 for n in [a, b]):
        raise ValueError((a,b))
    return op.pow(a, b)
operators[ast.Pow] = power

或者限制中间结果的大小:

import functools

def limit(max_=None):
    """Return decorator that limits allowed returned values."""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            ret = func(*args, **kwargs)
            try:
                mag = abs(ret)
            except TypeError:
                pass # not applicable
            else:
                if mag > max_:
                    raise ValueError(ret)
            return ret
        return wrapper
    return decorator

eval_ = limit(max_=10**100)(eval_)

Example

>>> evil = "__import__('os').remove('important file')"
>>> eval_expr(evil) #doctest:+IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError:
>>> eval_expr("9**9")
387420489
>>> eval_expr("9**9**9**9**9**9**9**9") #doctest:+IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
ValueError:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算字符串中的数学表达式 的相关文章

随机推荐

  • iOS 使用情况因 iPhone 尺寸不同而存在差异

    我有一个按钮 我希望根据所使用的 iPhone 类型具有不同的宽度 显然 7 Plus 的宽度更大 而 7 Plus 的宽度则更小 我单击按钮 单击 特征变化 选择 高度 更改每个 iPhone 的约束 然后单击 完成变化并构建 但它始终保
  • 从应用程序引擎访问计算引擎

    我有一个在计算引擎上运行的实例 它使用 Torch 来预测图像中的对象 我想制作一个简单的 Web 界面 用户可以使用该界面上传图像 将图像发送到服务器 计算引擎 预测对象并将列表返回给用户 在我的计算引擎 Ubuntu 14 04 中 这
  • 如何使用 distHaversine 函数?

    我试图在循环内使用 R 中的 distHavrsine 函数来计算数百行的某些纬度和经度坐标之间的距离 在我的循环中我有这样的代码 if distHaversine c file i long file i lat c file j lon
  • 如何用 C 语言制作自己的头文件?

    我尝试制作自己的头文件 但它不起作用vim says wget h 2 2 error invalid preprocessing directive ifndef WGET H wget h 3 2 error invalid prepr
  • 列出并连接到蓝牙设备

    我正在尝试让我的 Windows 平板电脑应用程序通过蓝牙与其他设备进行通信 首先我想扫描设备 然后我想连接到所选设备 我制作了一个简单的测试应用程序 空白首页并向其添加了一个按钮和一个列表框 然后我尝试了以下代码 我在其他地方找到了这样的
  • 如何删除HTTP响应头?

    我遇到一种情况 其中一个响应标头Content Disposition必须被删除 所以我想到编写一个servlet过滤器来做到这一点 但我意识到HttpServletResponse只有一个setHeader 方法 但没有方法删除它 我怎样
  • Django REST Framework 不以 PUT 形式显示值

    昨天我发了一个question并找到了解决该问题的方法 然而 该解决方案引发了另一个问题 请看一下问题 这样我就不必重复内容了 在可浏览 API 中 class name 的值不会显示在 PUT 表单中 呈现的 HTML 看起来像这样 di
  • 在oracle plsql中使用触发器填充代理键的优点

    我正在开发一个代码库 它具有以下类型的模式来生成表的代理键 create or replace TRIGGER TEST TRIG BEFORE INSERT OR UPDATE ON my table REFERENCING NEW AS
  • 更改 JavaFX 8 DatePicker 中的语言

    将 DatePicker 添加到我的应用程序时 我得到以下信息 我认为这是因为我在计算机上使用希伯来语 如何将 DatePicker 的语言更改为英语 您可以为 Java 虚拟机调用实例定义默认区域设置 Locale setDefault
  • 找到字符串中最长的单词

    目前正在尝试找出如何找到字符串中最长的单词 我的研究已经让我有所收获 我在 SO 上找到了一个代码 它显示了最长单词中的字母数量 Example function longest str var words str split var lo
  • FileUtils.mv 抛出 Invalid char \302 和 \255 异常

    当我运行下面的代码时CodeRunner或者从命令行我收到以下错误 Untitled rb 25 Invalid char 302 in expression Untitled rb 25 Invalid char 255 in expre
  • 从母版页调用部分视图时出现 ASP.NET MVC 堆栈溢出异常

    当我尝试从主控调用部分视图时 出现堆栈溢出错误 部分视图
  • Android 上的 OMA DRM v1 和 v2 支持

    Are OMA DRMAndroid 支持 v1 和 v2 吗 如果没有 有计划吗 是否有任何第三方库可以实现 OMA DRAM v1 和 v2 简短的回答是它不存在 但看起来有 3rd party 库 From 邮件列表 仅支持前向锁定
  • 片段单元测试:launchFragment 抛出 ClassCastException

    我试图在单元测试中调用 Fragment 类中的方法 但我不断收到错误java lang ClassCastException androidx fragment app testing FragmentScenario EmptyFrag
  • 我如何知道函数的参数数量?

    我们如何知道一个函数有多少个参数 例如 对于给定的函数f 我想做 if arg number f 0 f else if arg number f 1 f FALSE nargs 将检查函数内参数的数量 函数的参数数量 Edit forma
  • 使用 JNI 将 float* 转换为 jfloatArray

    我在 C 函数中获得了一个 float 我需要将其转换为 jfloatArray 以返回到我的 Java 代码 如何将 float 转换为 jfloatArray Thanks 要将 float 转换为 jfloatArray 可以使用 N
  • 如何将文件夹添加到 java 构建路径作为库,其中包含多个 jar 或条目?

    首先 我想说非常感谢 Rich seller 解决了我以编程方式更改 eclipse java 构建路径中的条目顺序的查询 我想将我的 Library 文件夹添加到 java 构建路径 其中有几个 jar 它的行为应该像类路径容器 我尝试使
  • 将 ISO 格式的日期转换为 DATETIME

    我正在使用 SQL Server Management Studio 编写 SQL 查询 并且有一些 ISO 日期格式的 NVARCHAR 类型值 例如 20130302T164800 我需要将它们转换为 DATETIME 我尝试过Conv
  • 分解除括号之外的字符串?

    我正在尝试通过垂直条来爆炸一根弦 这是最简单的部分 但是 我不希望分割影响括号内的子字符串 这意味着我需要一个字符串 例如 Hello sir maam Hi there 爆炸成 Array 0 gt Hello sir maam 1 gt
  • 计算字符串中的数学表达式

    stringExp 2 4 intVal int stringExp Expected value 16 这将返回以下错误 Traceback most recent call last File