公众号里链接的网站怎么做的,济南网站开发公司排名,乐清市城乡建设局网站,上海公司起名目录 问题分析与解答evalsympy消去法逆波兰表达式拓展思考参考资料 问题
用代码实现一个method#xff0c;这个method的入参是一个字符串#xff0c;这个字符串是一个四则运算的算式#xff0c;比如“12*34/2-3”#xff1b;返回值是这个算式的运算结果#xff0c;比如“… 目录 问题分析与解答evalsympy消去法逆波兰表达式拓展思考参考资料 问题
用代码实现一个method这个method的入参是一个字符串这个字符串是一个四则运算的算式比如“12*34/2-3”返回值是这个算式的运算结果比如“12*34/2-3”的返回值是6为了简化这个题目这个入参的算式只包含加减乘除不包含括号
分析与解答
四则运算是数学常见的运算法则有现成的函数或者第三方库来解决也可以自己写一个method。下面分别介绍几种方法,按照由易到难的顺序
eval
由于入参的算式只包含加减乘除不包含括号所以可以采用eval直接算但是eval会存在注入风险。
# -*- encoding: utf-8 -*-Project : Arithemitc
Desc : 字符串转四则运算
Time : 2024/05/25 09:28:12
Author : 帅帅de三叔,zengbowengood163.comimport re
import operatordef arithmetic(expression):eval直接算return eval(expression)if __name____main__:input 12-3/2*2 #例子12-3/2*2, 12*34/2-3result arithmetic(input)print(result)
sympy
sympy 是专用的数学符号计算库在处理方程时候非常强大但是运行效率稍微慢了点
import re
import operator
from sympy import sympify, simplifydef Arithemtic(origin_str): 去除优先级乘法和除法运算expr str(origin_str) #转字符串result simplify(sympify(expr))return resultif __name____main__:input 12-3/2*2 #12-3/2*2result Arithemtic(input)print(result)消去法
倘若优先级运算“x”和“/”不相邻此时可以先对“x和”/“先单独计算把“x和”/“前后两个数字先计算和合二为一处理完就只有”“和”-“两种运算了下面这个可以实现“x”和“/”不相邻的情形“x”和“/”相邻的情况还没想好。
# -*- encoding: utf-8 -*-Project : Arithemitc
Desc : 字符串转四则运算
Time : 2024/05/25 09:28:12
Author : 帅帅de三叔,zengbowengood163.comimport re
import operatordef Arithemtic(origin_str): 去除优先级乘法和除法运算expr str(origin_str) #转字符串digits re.findall(r\d, expr) #提取数字串digits [eval(i) for i in digits] #转数字operations re.findall(r[\-*/], expr) #提取运算符号print(digits, operations)operators {: operator.add, -: operator.sub, *: operator.mul, /: operator.truediv} #四则运算映射for i in range(len(operations)): #对运算列表循环try:if operations[i] * or operations[i] /: #如果有乘法除法先算去除print(i, operations[i], digits[i], digits[i1])digits[i] operators[operations[i]](digits[i], digits[i1]) #合并运算print(digits, operations)digits.pop(i1) #剔除第i1位数字operations.pop(i) #剔除第i位算符 except:continueprint(digits, operations) #此时只有加减运算for j in range(len(operations)): # print(digits[j]) digits[j1] operators[operations[j]](digits[j], digits[j 1]) #咬合向前逐步运算result digits[-1]print(result)return resultif __name____main__:input 12*34/2-3 #12-3/2*2result Arithemtic(input)逆波兰表达式
查阅资料说逆波兰表达式法可以用于解决没有括号的字符串四则运算计算步骤如下
1字符串四则运算表达式转换为后缀表达式 2从左到右遍历表达式中的每个元素 3如果当前元素是数字将其压入栈中 4如果当前元素是运算符则取出栈顶的两个数字进行计算并将结果压入栈中 5当遍历完整个表达式后栈顶就是最终结果。
import redef infix_to_postfix(expression): # 运算符优先级字典越低越优先 precedence {: 1, -: 1, *: 2, /: 2} output [] op_stack [] # 辅助函数用于检查是否为运算符 def is_operator(token): return token in -*/ # 分割表达式为tokens tokens re.findall(r[\-*/]|\d, expression) for token in tokens: if token.isdigit(): # 如果是数字直接输出 output.append(token) elif is_operator(token): # 如果是运算符 # 弹出并输出所有优先级更高或等于当前运算符的运算符 while op_stack and is_operator(op_stack[-1]) and \precedence[op_stack[-1]] precedence[token]: output.append(op_stack.pop()) # 将当前运算符压入栈 op_stack.append(token) else: # 如果是非法字符抛出异常 raise ValueError(fInvalid token: {token}) # 弹出并输出所有剩余的运算符 while op_stack: output.append(op_stack.pop()) return .join(output) def evaluate_postfix(postfix_expr): stack [] for token in postfix_expr.split(): # 假设表达式是空格分隔的字符串 if token.isdigit(): # 如果是数字 stack.append(int(token)) else: # 如果是运算符 operand2 stack.pop() operand1 stack.pop() if token : result operand1 operand2 elif token -: result operand1 - operand2 elif token *: result operand1 * operand2 elif token /: # 注意这里没有处理除数为0的情况 result operand1 / operand2 else: raise ValueError(fInvalid operator: {token}) stack.append(result) return stack.pop() # 返回最终结果 # 示例
infix_expr 12-3/2*2
postfix_expr infix_to_postfix(infix_expr)
result evaluate_postfix(postfix_expr)
print(fPostfix expression: {postfix_expr})
print(fresult: {result})拓展思考
1根据乘法与除法的关系除以某个数等于乘以这个数的倒数可以将所有除法运算改成乘法运算这种改变只会改变运算符号的右侧不会动左侧的
2根据乘法是加法的简便运算将所有乘法改成加法运算这里存在一个非整数倍的问题需要用数值解法
3最后化成只有加法和减法的表达式因为是对字符串操作其中需要用到大量的正则运算和定位索引。
参考资料
1逆波兰表达式介绍及求值实现 https://blog.csdn.net/wenwenaier/article/details/121236053