没有括号的字符串四则运算

目录

  • 问题
  • 分析与解答
  • eval
  • sympy
  • 自己编写
  • 逆波兰表达式
  • 拓展思考
  • 参考资料

问题

用代码实现一个method,这个method的入参是一个字符串,这个字符串是一个四则运算的算式,比如“1+2*3+4/2-3”;返回值是这个算式的运算结果,比如“1+2*3+4/2-3”的返回值是6,为了简化这个题目,这个入参的算式只包含加减乘除,不包含括号

分析与解答

四则运算是数学常见的运算法则,有现成的函数或者第三方库来解决,也可以自己写一个method。下面分别介绍几种方法,按照由易到难的顺序

eval

由于入参的算式只包含加减乘除,不包含括号,所以可以采用eval直接算,但是eval会存在注入风险。

# -*- encoding: utf-8 -*-
'''
@Project :   Arithemitc
@Desc    :   字符串转四则运算
@Time    :   2024/05/25 09:28:12
@Author  :   帅帅de三叔,zengbowengood@163.com
'''
import re
import operatordef arithmetic(expression):"""eval直接算"""return eval(expression)if __name__=="__main__":input = "1+2-3/2*2" #例子1+2-3/2*2, 1+2*3+4/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 = "1+2-3/2*2" #1+2-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三叔,zengbowengood@163.com
'''
import 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[i+1])digits[i] = operators[operations[i]](digits[i], digits[i+1]) #合并运算print(digits, operations)digits.pop(i+1) #剔除第i+1位数字operations.pop(i) #剔除第i位算符  except:continueprint(digits, operations)  #此时只有加减运算for j in range(len(operations)): # print(digits[j])     digits[j+1] =  operators[operations[j]](digits[j], digits[j + 1]) #咬合向前逐步运算result = digits[-1]print(result)return resultif __name__=="__main__":input = "1+2*3+4/2-3" #1+2-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(f'Invalid 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(f"Invalid operator: {token}")  stack.append(result)  return stack.pop()  # 返回最终结果  # 示例  
infix_expr = "1+2-3/2*2"   
postfix_expr = infix_to_postfix(infix_expr)  
result = evaluate_postfix(postfix_expr)
print(f"Postfix expression: {postfix_expr}")
print(f"result: {result}")

拓展思考

1,根据乘法与除法的关系,除以某个数等于乘以这个数的倒数,可以将所有除法运算改成乘法运算,这种改变只会改变运算符号的右侧不会动左侧的;

2,根据乘法是加法的简便运算将所有乘法改成加法运算,这里存在一个非整数倍的问题需要用数值解法;

3,最后化成只有加法和减法的表达式,因为是对字符串操作,其中需要用到大量的正则运算和定位索引。

参考资料

1,逆波兰表达式介绍及求值实现
https://blog.csdn.net/wenwenaier/article/details/121236053

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/15380.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【知识拓展】ngrok-高性价比的内网穿透工具

前言 使用google colab运行的web应用无法打开进行测试。 第一时间想到是否有相关工具能将内网映射到外网供访问。于是找到了ngrok。 ngrok 是什么,我们为什么要使用它? ngrok官网是一个全球分布的反向代理,无论您在哪里运行,它…

【车载开发系列】Autosar中的VFB

【车载开发系列】Autosar中的VFB # 【车载开发系列】Autosar中的VFB 【车载开发系列】Autosar中的VFB一. 什么是VFB二. VFB的优点与缺点1)VFB的缺点2)VFB的好处 三. RTE与VFB之间关系四. 总线架构模式 一. 什么是VFB Virtual Functional Bus。它就是虚拟…

解决Vue项目部署到服务器之后前端向后端发送请求报错404的问题(centos使用docker实现nginx的反向代理)

场景重现: 由于现在流行前后端分离的部署方式,但是按照正确方法部署(如何部署可参考:)之后,发现明明前后端都部署好了并且运行成功,但是前端发送的请求都是404。明明在vue项目中配置了跨域的相…

【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结

💓 博客主页:从零开始的-CodeNinja之路 ⏩ 收录文章:【Spring Boot】深度复盘在开发搜索引擎项目中重难点的整理,以及遇到的困难和总结 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 什么是搜索引…

Sql语句DML操作 增删改

DML 数据操作 增删改 插入数据 方式1: INSERT INTO 表名(列1,列2……,列n) VALUES(值1,值2…..,值n);方式2: INSERT INTO 表名 set 列名1值1,..列名;方式3: INSERT INTO 表名(列1,列2……,列n) VALUES(值1,值2…..,值n),(值1,值2…..,值n);方式4: INSERT INTO 表名(列1,列2……

AJAX初级

AJAX的概念: 使用浏览器的 XMLHttpRequest 对象 与服务器通信 浏览器网页中,使用 AJAX技术(XHR对象)发起获取省份列表数据的请求,服务器代码响应准备好的省份列表数据给前端,前端拿到数据数组以后&#xf…

常见网络协议及端口号

https://www.cnblogs.com/Snail-yellow/p/17722411.html 常见的网络协议-腾讯云开发者社区-腾讯云 常见的网络协议知识整理_五种常用的网络协议-CSDN博客 端口 协议 常见的网络协议_计算机网络协议有哪些csdn-CSDN博客 ​​​​​​​​​​​​​​协议 常见的网络协议知…

二叉树前中后序遍历

前言 个人小记 一、代码如下 #include<stdio.h> #include <stdlib.h> #include <time.h> #define MAX_NODE 10 #define p()\ {\printf("\n");\ } typedef struct Node {int key;int lfag,rfag;struct Node *lchild,*rchild; }Node;Node* init_no…

TENT: FULLY TEST-TIME ADAPTATION BY ENTROPY MINIMIZATION--论文笔记

论文笔记 资料 1.代码地址 https://github.com/DequanWang/tent 2.论文地址 https://arxiv.org/abs/2006.10726 1论文摘要的翻译 在这种完全测试时适应的情况下&#xff0c;模型只有测试数据和自身参数。我们建议通过测试熵最小化&#xff08;tent&#xff09;进行适应&…

虚拟化技术[2]之存储虚拟化

存储虚拟化 存储虚拟化简介存储虚拟化一般模型存储虚拟化实现方式基于主机存储虚拟化基于存储设备存储虚拟化基于网络存储虚拟化 案例分析&#xff1a;VMFSVMFS功能 存储虚拟化简介 存储虚拟化&#xff1a;将存储网络中的各个分散且异构的存储设备按照一定的策略映射成一个统一…

C++学习笔记(19)——模板

目录 模板参数与非类型模板参数 模板参数 类型模板参数——传递类型 非类型模板参数——传递数量 C11希望array替代静态数组&#xff0c;但实际上vector包揽了一切 模板总结 优点&#xff1a; 缺点&#xff1a; 模板特化&#xff1a;针对某些类型进行特殊化处理 特化…

大模型的快速成长

大模型的关键要素有三点,数据&#xff0c;算法和进化的方式. 首先&#xff0c;数据是基础。大量且高质量的数据对于大模型的成长至关重要。不断收集涵盖更广泛领域、更丰富细节的数据&#xff0c;并且确保数据的准确性和代表性。只有在充分的数据滋养下&#xff0c;大模型才能更…

P451 try-Catch异常处理

//基本使用演示代码 public static void main(String[] args) { int num1 10; int num2 0; try { int res num1 / num2; }catch (Exception e) { System.out.println(e.getMessage()); } } public class TryCatchDetail { public static void main(String[] args) { //1. 如…

ubuntu20.04 终端 设置字体大小

##ubuntu20.04 Terminal 终端 设置字体大小 ##打开Terminal 终端&#xff0c;点击Preferences设置字体大小 ##点击unnamed选项卡&#xff0c;打钩Custom font 设置 字体大小

SQL、Mongo、Redis一般适用于那些场景

在一个项目中同时使用 MySQL、Redis 和 MongoDB 是相对常见的做法&#xff0c;因为它们各自具有不同的特点和适用场景&#xff0c;可以组合使用以满足不同的需求。下面是它们的一些常见用途和特点&#xff1a; MySQL&#xff1a; 关系型数据库&#xff1a; MySQL 是一个传统的关…

topsis综合评价法

TOPSIS综合评价法&#xff08;Technique for Order Preference by Similarity to Ideal Solution&#xff09;是一种多目标决策分析中的有效方法&#xff0c;也被称为优劣解距离法。该方法基于评价对象与理想化目标的接近程度进行排序&#xff0c;从而评估现有对象的相对优劣。…

三前奏:获取/ 读取/ 评估数据【数据分析】

各位大佬好 &#xff0c;这里是阿川的博客 &#xff0c; 祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 前面的博客 数据分析—技术栈和开发环境搭建 …

二叉树——堆详解

目录 前言&#xff1a; 一、堆的结构 二、向上调整和向下调整 2.1 向上调整 2.2 向下调整 2.3 向上调整和向下调整时间复杂度比较 三、堆的实现 3.1 堆的初始化 3.2 堆的销毁 3.3 堆的插入 3.4堆的删除 3.5 取堆顶元素 3.6 对堆判空 四、堆排序 五、TOP-K 问题 六、代码总…

基于Vue2与3版本的Element UI与Element Plus入门

基于Vue2与3版本的Element UI与Element Plus入门 Element UI 入门安装引入 Element UI使用组件 Element Plus 入门安装引入 Element Plus使用组件 常用组件自定义主题兼容性和升级社区和支持 Element UI 入门 Element UI 是基于 Vue 2.0 的桌面端组件库&#xff0c;它提供了一…

js报错replaceAll不是一个function(特定设备),如何在平板中展示前端控制台

工作记录-前端——replaceAll方法不兼容以及如何在平板调试前端代码&#xff08;看到控制台报错信息&#xff09; 创作场景如何在平板显示控制台第一步第二步 关于replaceAll不兼容问题相同点不同点 如何识别粘贴操作中的换行符下课 创作场景 公司项目要求兼容pc、平板、手机等…