WPS Python脚本合集(一):eval函数直接计算表达式

Excel表格中的EVALUATE函数可以将文本字符串当作公式,进行计算并返回结果,常用于动态公式生成或处理以文本形式存储的算式。

Python语言中的eval() 是一个危险的函数,如果使用不受信任的字符串作为表达式,则可能导致代码注入漏洞,因此,应谨慎使用 eval() 函数,并确保仅执行可信任的字符串表达式。

完整文章链接见微信公众号:https://mp.weixin.qq.com/s/KXSaC_VQcr5W-punySRUKg

一、多维表格结构

1、表名:evaluate方法

2、视图名:表格视图

3、字段设置:

◉ 字段名称:表达式 - 字段类型:文本 - 禁止录入重复值:否 - 默认值:无;

◉ 字段名称:计算结果 - 字段类型:文本 - 禁止录入重复值:否 - 默认值:无;

二、Python脚本批量计算【危险版】

前面有讲到eval() 是一个危险的函数,如果使用不受信任的字符串作为表达式,则可能导致代码注入漏洞,下面来做下对比演示

2.1 代码逻辑解释

首先使用dbt()函数读取名为'evaluate方法'的数据表数据,并输出变量类型和具体数据;

接着使用iterrows()遍历DataFrame,同时获取索引和行数据,如果空值或NaN会跳过,如果表达式格式不规范,会输出错误结构

最后打印最终的计算结果

import pandas as pd

expression = dbt(sheet_name='evaluate方法')
print("expression 变量类型:", type(expression))
print("expression 变量值:")
print(expression)

# 直接使用iterrows()遍历DataFrame,同时获取索引和行数据
for index, row in expression.iterrows():  
    expr = row['表达式']

    # 跳过空值或NaN
    if pd.isna(expr):
        print(f"索引 {index}: 跳过空表达式")
        continue

    try:
        # 安全地计算表达式
        result = eval(expr)
        update_dbt({"_rid": index, "计算结果": result})
        print(f"索引 {index}: 表达式 '{expr}' 计算结果: {result}")
    except Exception as e:
        print(f"索引 {index}: 计算表达式 '{expr}' 时出错: {str(e)}")

print("\n最终结果:")
print(dbt(sheet_name='evaluate方法'))

2.2 正常数据演示

以图中数据进行演示

控制台输出情况

动图演示

2.3 恶意代码数据演示

假设存在一个名为'待删除数据表'的数据表内存在数据

此时数据表'evaluate方法'表达式列中存在如下数据

update_dbt({"_rid": "DVR", "计算结果": "测试代码注入"}),这行代码代表在索引值为DVR行中更新计算结果列的内容为"测试代码注入"

delete_dbt(sheet_name='待删除数据表'),这行代表删除名为'待删除数据表'的数据表全部内容

一不小心就删库跑路咯O(∩_∩)O

同样运行脚本,控制台输出情况

动图演示

三、Python脚本批量计算【输入校验版】

3.1 代码逻辑解释

如果真的需要使用eval函数,我们可以对函数输入的内容做校验或在受限制的环境下运行,如检查字符串是否仅包含安全的数学表达式字符,或只允许访问数学模块中的安全函数和常量,禁用内置函数等方法,具体代码如下:

import pandas as pd
import re
import ast

def is_math_expression(expr_str):
    """
    使用正则表达式检查字符串是否仅包含安全的数学表达式字符。
    允许数字、基本运算符、空格和常用数学常量及函数。
    """
    if not isinstance(expr_str, str):
        return False
    # 正则表达式模式:允许数字、加减乘除、乘方、括号、小数点、空格、常用数学函数和常量
    pattern = r'^[\d\s+\-*/().^eπsincoatanlogsqrtabs,]+$'
    # 检查是否包含可能危险的关键字或函数调用(简易过滤)
    blacklist = ['__', 'import', 'os', 'sys', 'exec', 'eval', 'open', 'file', 'lambda']
    if any(keyword in expr_str for keyword in blacklist):
        return False
    return re.match(pattern, expr_str) is not None

def safe_eval(expr_str):
    """
    相对安全地评估数学表达式。
    首先尝试使用 ast.literal_eval,如果失败且表达式看似复杂但安全,则使用 eval 受限环境。
    """
    try:
        # 尝试直接解析字面量(最安全)
        return ast.literal_eval(expr_str)
    except (ValueError, SyntaxError):
        # 如果 ast.literal_eval 失败,但表达式通过安全检查,则在受限环境中使用 eval
        if is_math_expression(expr_str):
            try:
                # 创建受限的全局环境,只允许访问数学模块中的安全函数和常量
                safe_globals = {
                    "__builtins__": None,  # 禁用内置函数
                    "sin": __import__('math').sin,
                    "cos": __import__('math').cos,
                    "tan": __import__('math').tan,
                    "sqrt": __import__('math').sqrt,
                    "log": __import__('math').log,
                    "log10": __import__('math').log10,
                    "e": __import__('math').e,
                    "pi": __import__('math').pi,
                    "abs": abs,
                    "pow": pow,
                    "round": round,
                }
                return eval(expr_str, {"__builtins__": {}}, safe_globals)
            except Exception as e:
                raise ValueError(f"计算表达式时出错: {str(e)}")
        else:
            raise ValueError("表达式包含不安全字符或结构")

# 获取包含表达式的 DataFrame
expression_df = dbt(sheet_name='evaluate方法')
print("expression 变量类型:", type(expression_df))
print("expression 变量值:")
print(expression_df)

# 检查 DataFrame 是否包含 '表达式' 列
if '表达式' not in expression_df.columns:
    raise ValueError("DataFrame 中未找到 '表达式' 列")

# 遍历 DataFrame 的每一行
for index, row in expression_df.iterrows():
    expr = row['表达式']
    
    # 跳过空值或 NaN
    if pd.isna(expr):
        print(f"索引 {index}: 跳过空表达式")
        continue
        
    # 检查表达式是否为字符串
    if not isinstance(expr, str):
        print(f"索引 {index}: 跳过非字符串表达式 '{expr}'")
        continue
        
    print(f"索引 {index}: 正在处理表达式 '{expr}'")
    
    try:
        # 检查是否为数学表达式
        if is_math_expression(expr):
            # 安全地计算表达式
            result = safe_eval(expr)
            # 更新数据库(假设 update_dbt 函数已定义)
            update_dbt({"_rid": index, "计算结果": result})
            print(f"索引 {index}: 表达式 '{expr}' 计算结果: {result}")
        else:
            print(f"索引 {index}: 表达式 '{expr}' 被拒绝,因为它不是安全的数学表达式")
    except Exception as e:
        print(f"索引 {index}: 计算表达式 '{expr}' 时出错: {str(e)}")

print("\n最终结果:")
result_df = dbt(sheet_name='evaluate方法')
print(result_df)

3.2 含恶意代码数据演示

以图中数据进行演示

控制台输出情况,可以看到不符合规范的异常数据会被拦截,输出报错结果

动图演示:

四、Python脚本+自动化流程【输入校验版】

4.1 代码逻辑解释

其实内容和前面的大差不差,主要是前面需要获取自动化流程传过来的值,

受文章字数限制,具体代码见微信公众号链接:https://mp.weixin.qq.com/s/KXSaC_VQcr5W-punySRUKg

4.2 自动化流程配置

直接上图

4.3 动图演示

广东省
浏览 270
3
3
分享
3 +1
2
3 +1
全部评论 2
 
网管别回我帖子
向小林同志学习
· 四川省
回复
bokuto
互相学习,一起成长
· 广东省
回复