Golang通过栈实现表达式运算(中缀表达式转后缀表达式解析语法)

Golang通过栈实现表达式运算(中缀表达式转后缀表达式解析语法)

需求背景:将string表达式数组 [title == AUSU && ( header == Wecome || brand != AC68U )] 解析并使用ES查询得到运算结果。

分析:带有括号的表达式,需要根据优先级解析,可将中缀表达式转换为后缀表达式,去除括号

1. 定义栈结构

package scanner_utilsimport "errors"type Stack []interface{}func (stack Stack) Len() int {return len(stack)
}func (stack Stack) IsEmpty() bool {return len(stack) == 0
}func (stack Stack) Cap() int {return cap(stack)
}func (stack *Stack) Push(value interface{}) {*stack = append(*stack, value)
}func (stack Stack) Top() (interface{}, error) {if len(stack) == 0 {return nil, errors.New("Stack out of index, len is 0")}return stack[len(stack)-1], nil
}func (stack *Stack) Pop() (interface{}, error) {theStack := *stackif len(theStack) == 0 {return nil, errors.New("Stack out of index, len is 0")}value := theStack[len(theStack)-1]*stack = theStack[:len(theStack)-1]return value, nil
}func (stack *Stack) Peek() interface{} {theStack := *stackvalue := theStack[len(theStack)-1]return value
}

2. 中缀表达式转后缀表达式

// [title==AUSU && ( header==Wecome || brand!=AC68U )] => [title==AUSU header==Wecome brand!=AC68U || &&]
func InfixToSuffixExpression(infixList []string) []string {var suffixList []string// 符号栈stack := Stack{}for _, item := range infixList {if item != "(" && item != ")" && item != "&&" && item != "||" { // 不是符号,直接添加到数组suffixList = append(suffixList, item)} else {if item == "(" { // 左括号,直接入符号栈stack.Push(item)} else if item == ")" { // 右括号,将符号栈的运算符弹出,直到遇到左括号for {if stack.IsEmpty() {// 语法错误break}if "(" == stack.Peek().(string) { // 遇到左括号,将左括号弹出,结束循环stack.Pop()break}oper, _ := stack.Pop()suffixList = append(suffixList, oper.(string))}} else {// item的优先级小于等于符号栈顶元素优先级时,将符号栈顶元素弹出并添加到数组// item的优先级大于符号栈顶元素优先级时,将item入栈for {if stack.IsEmpty() || getPriority(stack.Peek().(string)) < getPriority(item) {stack.Push(item)break}oper, _ := stack.Pop()suffixList = append(suffixList, oper.(string))}}}}// 将符号栈剩余的元素依次弹出for {if stack.IsEmpty() {break}oper, _ := stack.Pop()suffixList = append(suffixList, oper.(string))}return suffixList
}// 定义优先级
func getPriority(operator string) int {OR := 1AND := 2var resp intif operator == "&&" {resp = AND}if operator == "||" {resp = OR}return resp
}

3. 遍历后缀表达式进行运算,并拼接ES查询语法

// 输入参数:[title==AUSU header==Wecome brand!=AC68U || &&]
func jointSearchDsl(suffixExpreList []string) (*elastic.BoolQuery, error) {expreStack := scanner_utils.Stack{}queryMap := make(map[string]*elastic.BoolQuery)index := 1var err errorfor _, item := range suffixExpreList {if item != "&&" && item != "||" { // 不是运算符,直接入栈expreStack.Push(item)} else { // 是运算符,弹出栈中两个元素进行计算expre1, _ := expreStack.Pop()expreStr1 := expre1.(string)expre2, _ := expreStack.Pop()expreStr2 := expre2.(string)// 解析两个表达式的K-Vkv1BoolQuery := elastic.NewBoolQuery()if !strings.HasPrefix(expreStr1, "doneExpre") { // 需要处理kv1BoolQuery, err = getExpresDsl(expreStr1)if err != nil {return nil, err}} else {kv1BoolQuery = queryMap[expreStr1]}kv2BoolQuery := elastic.NewBoolQuery()if !strings.HasPrefix(expreStr2, "doneExpre") { // 需要处理kv2BoolQuery, err = getExpresDsl(expreStr2)if err != nil {return nil, err}} else {kv2BoolQuery = queryMap[expreStr2]}// 根据运算符使用must或者should拼接boolQueryOper := elastic.NewBoolQuery()if item == "&&" {boolQueryOper.Must(kv1BoolQuery, kv2BoolQuery)}if item == "||" {boolQueryOper.Should(kv1BoolQuery, kv2BoolQuery)}index++// 写一个标识到栈,当作已处理的表达式doneExpre := "doneExpre" + strconv.Itoa(index)expreStack.Push(doneExpre)queryMap[doneExpre] = boolQueryOper}}// 循环结束,取出最后的一个元素,获取对应的boolQueryexpreN, _ := expreStack.Pop()boolQuery := elastic.NewBoolQuery()if !strings.HasPrefix(expreN.(string), "doneExpre") {boolQuery, err = getExpresDsl(expreN.(string))if err != nil {return nil, err}} else {boolQuery = queryMap[expreN.(string)]}return boolQuery, nil
}// 输入参数:header==Wecome
// 将每一个表达式解析,拼接ES query dsl
func getExpresDsl(expre string) (*elastic.BoolQuery, error) {boolQuery := elastic.NewBoolQuery()// TODO...return boolQuery, nil
}

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

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

相关文章

jvm的垃圾回收算法有哪些

jvm的垃圾回收算法有标记-清除、复制、标记-整理、分代回收算法&#xff0c;它们分别有不同的实现&#xff1a; 一、标记-清除算法 利用可达性分析算法分析之后&#xff0c;将未被标记的对象[即不可达对象]清除&#xff0c;以便回收它们所占用的内存。 缺点&#xff1a; 1、需…

flask------消息闪现 flash

1介绍 flask提供了一个非常有用的flash()函数&#xff0c;它可以用来“闪现”需要提示给用户的消息&#xff0c;比如当用户登录成功后显示“欢迎回来&#xff01;”。在视图函数调用flash()函数&#xff0c;传入消息内容&#xff0c;flash&#xff08;&#xff09;函数把消息存…

TPlink DDNS 内网穿透?外网访问设置方法

有很多小伙伴都想知道&#xff1a;TPlink路由器怎么设置DDNS内网穿透&#xff1f;今天&#xff0c;小编就给大家分享一下TPlink DDNS 外网访问设置方法&#xff0c;下面是图文教程&#xff0c;帮助新手快速入门DDNS设置。 本文介绍的是云路由器TP-LINK DDNS的设置方法。TP-LIN…

R-Meta分析教程

详情点击链接&#xff1a;R-Meta模型教程 一&#xff1a;Meta分析的选题与文献计量分析CiteSpace应用 1、Meta分析的选题与文献检索 1)什么是Meta分析&#xff1f; 2)Meta分析的选题策略 3)文献检索数据库 4)精确检索策略&#xff0c;如何检索全、检索准 5)文献的管理与…

浏览器同源策略

浏览器同源策略 同源策略&#xff1a;是一个重要的浏览器的安全策略&#xff0c;用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互 它能帮助阻隔恶意文档&#xff0c;减少可能被攻击的媒介 例如&#xff1a;被钓鱼网站收集信息&#xff0c;使用ajax发起…

DevOps系列文章之 Docker 安装 NFS 服务器

Docker 安装 NFS 服务器 环境&#xff1a; 192.186.2.105 NFS 服务器 192.168.2.106 Client 客户端 安装 一、服务器端 https://github.com/f-u-z-z-l-e/docker-nfs-server 1、创建目录 mkdir /nfsdata mkdir -p /docker/nfs/2、启动脚本 vim start.sh# 内容 docker run …

[国产MCU]-BL602开发实例-GPIO控制

GPIO与控制 文章目录 GPIO与控制1、GPIO介绍2、GPIO管理相关API介绍3、硬件准备4、软件准备5、代码实现3.1 GPIO输出3.2 GPIO输入3.3 GPIO中断BL602的GLB(Global Register)是芯片通用全局设定模块,主要包含了时钟管理、复位管理、总线管理、内存管理以及GPIO管理等功能。 本文…

shell脚本自动打包部署

1、安装git 2、使用Git克隆代码 3、安装Maven &#xff08;1&#xff09; tar -zxvf ** 解压文件 &#xff08;2&#xff09;修改配置 &#xff08;3&#xff09;source /etc/profile 重新加载一下文件 &#xff08;4&#xff09;mvn -version 查看版本号 已经安装成…

线程池的使用案例一

一、配置线程池 1、不推荐的方式 ExecutorService executorService Executors.newFixedThreadPool(); // 创建⼀个固定⼤⼩的线程池&#xff0c;可控制并发的线程数&#xff0c;超出的线程会在队列中等待&#xff1b; ExecutorService executorService Executors.newCache…

基于Java+SpringBoot+Vue的篮球竞赛预约平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

C# 简单模拟 程序内部 消息订阅发布功能

文章目录 前言模拟消息订阅发布使用注意事项 前言 我想做个简单的消息发布订阅功能&#xff0c;但是发现好像没有现成的工具类。要么就是Mqtt这种消息订阅发布。但是我只想程序内部进行消息订阅发布&#xff0c;进行程序的解耦。那没办法了&#xff0c;只能自己上了 模拟消息…

【JavaSE】String类中常用的字符串方法(超全)

目录 1.求字符串的长度 2.判断字符串是否为空 3.String对象的比较 3.1 判断字符串是否相同 3.2 比较字符串大小 3.3 忽略大小写比较 4.字符串查找 5.转化 5.1 数值和字符串转化 5.1.1 数字转字符串 valueof 5.1.2 valueOf的其他用法 5.1.3 字符串转数字 5.2 大小写转…

【Shell】基础语法(二)

文章目录 一、Shell基本语法文件名代换命令代换算术代换转义字符引号 二、Shell脚本语法条件测试分支结构循环 三、总结 一、Shell基本语法 文件名代换 用于匹配的字符称为通配符&#xff08;Wildcard&#xff09;&#xff0c;如&#xff1a;* ? [ ] 具体如下&#xff1a; *…

3个月拿下华为测试岗,早知道华为这么好进,我就...

先说一下我的情况&#xff0c;某211本科计算机专业&#xff0c;之前在深圳那边做了大约半年多少儿编程老师&#xff0c;之后内部平调回长沙这边&#xff0c;回来之后发现有点难&#xff0c;这边可能是业绩难做&#xff0c;虚假承诺很厉害&#xff0c;要给那些家长虚假承诺去骗人…

暗黑版GPT流窜暗网 降低犯罪门槛

随着AIGC应用的普及&#xff0c;不法分子利用AI技术犯罪的手段越来越高明&#xff0c;欺骗、敲诈、勒索也开始与人工智能沾边。 近期&#xff0c;专为网络犯罪设计的“暗黑版GPT”持续浮出水面&#xff0c;它们不仅没有任何道德界限&#xff0c;更没有使用门槛&#xff0c;没有…

代码随想录一刷总结

为期60天的代码随想录算法训练营结束了&#xff0c;中间想放弃过&#xff0c;敷衍过&#xff0c;但是最终还是完成了&#xff0c;给我自己和打满60天卡的小伙伴们一个赞。这60天的从一个算法小白到刚刚入门&#xff0c;虽然只是小小一步&#xff0c;却并不容易&#xff0c;至少…

EtherCAT转Profinet网关连接西门子PLC与凯福科技总线步进驱动器通讯

西门子S7-1200/1500系列的PLC&#xff0c;采用Profinet实时以太网通讯协议&#xff0c;需要连接带EtherCAT的通讯功能的伺服驱动器等设备&#xff0c;就必须进行通讯协议转换。捷米特JM-EIP-RTU系列的网关提供了&#xff0c;快速可行的解决方案 捷米特JM-ECTM-PN在PROFINET一侧…

tomcat

1. 简述静态网页和动态网页的区别。 静态网页是指在服务器存储的网页内容保持不变&#xff0c;不会根据用户的请求或其他条件而改变。它的内容是固定的&#xff0c;无法根据用户的不同需求进行个性化或实时更新。静态网页一般由HTML、CSS和JavaScript等静态资源组成&#xff0…

linux文件描述符fd

文件描述符 fd是一个>0 的整数 每打开一个文件&#xff0c;就创建一个文件描述符&#xff0c;通过文件描述符来操作文件 预定义的文件描述符: 0:标准输入&#xff0c;对应于已打开的标准输入设备(键盘) 1:标准输出&#xff0c;对应于已打开的标准输出设备(控制台) 2.标准错误…

java异常机制分析

java异常机制分析 本文实例分析了java的异常机制&#xff0c;分享给大家供大家参考。相信有助于大家提高大家Java程序异常处理能力。具体分析如下&#xff1a; 众所周知&#xff0c;java中的异常(Exception)机制很重要&#xff0c;程序难免会出错&#xff0c;异常机制可以捕获…