最近项目中接到一个需求,就是将where条件后的 条件关系转换成 指定的要求作为入参,
例如:where a and b or c 需转换成 a,b,and,c,or的格式,因为之前没有了解过中缀式后缀式,各种百度也没有搜索到,然后就自己根据代码实现,但是写的太底层太繁琐了,同事看到我的代码后就告诉我有中缀式转后缀式,我就又去百度了,但是都是算术表达式的转换,大多都是用char[]字符数组来实现,百度了一圈也没有找到合适的,又是那个同事,他给了我一个链接,只要稍微改改代码就可以实现了,参考链接为:https://blog.51cto.com/11290909/2085571
然后我就将 链接里面的优先级和相应运算符改成了我所需要的,然后测试了下 可以符合要求,修改后的代码如下,截图红色标注的地方即使我修改的地方:
public class PreToAfterUtil { private static String leftChar = "("; private static String rightChar = ")"; private static Map<String, Integer> operationSymbolMap = new HashMap<>(); static { //初始化符号和优先级 operationSymbolMap.put(")",00); //右括号需匹配左括号,故优先级最低 operationSymbolMap.put("and",20); operationSymbolMap.put("or",10); operationSymbolMap.put("(",30); //初始化符号和优先级 // operationSymbolMap.put(")",00); //右括号需匹配左括号,故优先级最低 // operationSymbolMap.put("+",10); // operationSymbolMap.put("-",10); // operationSymbolMap.put("*",20); // operationSymbolMap.put("/",20); // operationSymbolMap.put("(",30); } public static Queue parsePre(String[] strings) { Stack<String> preStack = new Stack<String>(); Queue<String> queue = new LinkedBlockingQueue(); int i = 0; while(i<strings.length && Objects.nonNull(strings[i])) { if((!"(".equals(strings[i].trim()))&&(!")".equals(strings[i].trim()))&&(!"or".equals(strings[i].trim()))&&(!"and".equals(strings[i].trim()))) { queue.add(strings[i]); }else if(StringUtils.isNotEmpty(strings[i])) { if(preStack.isEmpty()) { preStack.push(strings[i]); } else { String top = preStack.pop(); if(comparePriority(strings[i], top) < 0) { if(top.equals(leftChar)) { preStack.push(top); preStack.push(strings[i]); }else if(strings[i].equals(rightChar)) { appendTo(queue, top); preStack.pop(); } else{ appendTo(queue, top); popPre(preStack, strings[i], queue); preStack.push(strings[i]); //当前元素入栈 } } else { preStack.push(top); preStack.push(strings[i]); } } } i++; } while (!preStack.isEmpty()) { queue.add(preStack.pop()); } return queue; } /** * 递归比较当前元素与栈顶元素优先级 * @param preStatck * @param charTemp * @param queue */ public static void popPre(Stack<String> preStatck, String charTemp, Queue queue) { if(!preStatck.isEmpty()) { String top = preStatck.pop(); if(comparePriority(charTemp, top) <= 0) { //低于栈顶元素,成为后缀表达式一部分 appendTo(queue, top); popPre(preStatck, charTemp, queue); } else { preStatck.push(top); } } } private static void appendTo(Queue queue, String s) { if(!s.equals(leftChar) && !s.equals(rightChar)) { queue.add(s); } } /** * 比较优先级 * @param start * @param to * @return */ private static int comparePriority(String start, String to) { return operationSymbolMap.get(start).compareTo(operationSymbolMap.get(to)); } public static void main(String[] args) { String[] pre = new String[]{"(","name = 'xmd'","and","age = 18",")","or","status = 1"}; StringBuilder sb = new StringBuilder(); for (int i = 0; i < pre.length; i++) { sb.append(pre[i]); } System.out.println("前缀表达式:" + sb.toString()); Queue queue = new PreToAfterUtil().parsePre(pre); System.out.println("后缀表达式:" + queue.toString()); } }
可是随着测试的复杂度越来越深,我发现在给where条件后的关系字段加上括号后加在不同的地方会出现后缀表达式中出现括号或者缺少关系and或者or的情况,于是就开始定位问题,由于本人能力比较弱,定位了好久才解决了该问题,于是再次修改代码,修改后的代码如下:
package com.xmd.quartz.test.zhongzhuishi;
import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;
/**
* User: xumengdi
* Date: 2019/8/1
*/
public class PreToAfterUtil {
private static String leftChar = "(";
private static String rightChar = ")";
private static Map<String, Integer> operationSymbolMap = new HashMap<>();
static {
//初始化符号和优先级
operationSymbolMap.put(")",00); //右括号需匹配左括号,故优先级最低
operationSymbolMap.put("and",20);
operationSymbolMap.put("or",10);
operationSymbolMap.put("(",30);
//初始化符号和优先级
// operationSymbolMap.put(")",00); //右括号需匹配左括号,故优先级最低
// operationSymbolMap.put("+",10);
// operationSymbolMap.put("-",10);
// operationSymbolMap.put("*",20);
// operationSymbolMap.put("/",20);
// operationSymbolMap.put("(",30);
}
public static Queue parsePre(String[] strings) {
Stack<String> preStack = new Stack<String>();
Queue<String> queue = new LinkedBlockingQueue();
int i = 0;
while(i<strings.length && Objects.nonNull(strings[i])) {
if((!"(".equals(strings[i].trim()))&&(!")".equals(strings[i].trim()))&&(!"or".equals(strings[i].trim()))&&(!"and".equals(strings[i].trim()))) {
queue.add(strings[i]);
}else if(StringUtils.isNotEmpty(strings[i])) {
if(preStack.isEmpty()) {
preStack.push(strings[i]);
} else {
String top = preStack.pop();
if(comparePriority(strings[i], top) < 0) {
if(top.equals(leftChar)) {
preStack.push(top);
preStack.push(strings[i]);
}else if(strings[i].equals(rightChar)) {
appendTo(queue, top);
String top2 = preStack.pop();
if(top2.equals("or")||top2.equals("and")){
appendTo(queue, top2);
}
// if(!preStack.isEmpty()){
// preStack.pop();
// }
} else{
appendTo(queue, top);
popPre(preStack, strings[i], queue);
preStack.push(strings[i]); //当前元素入栈
}
} else {
preStack.push(top);
preStack.push(strings[i]);
}
}
}
i++;
}
while (!preStack.isEmpty()) {
String top = preStack.pop();
if(!top.equals(leftChar)&&!top.equals(rightChar)){
queue.add(top);
}
}
return queue;
}
/**
* 递归比较当前元素与栈顶元素优先级
* @param preStatck
* @param charTemp
* @param queue
*/
public static void popPre(Stack<String> preStatck, String charTemp, Queue queue) {
if(!preStatck.isEmpty()) {
String top = preStatck.pop();
if(comparePriority(charTemp, top) <= 0) {
//低于栈顶元素,成为后缀表达式一部分
appendTo(queue, top);
popPre(preStatck, charTemp, queue);
} else {
preStatck.push(top);
}
}
}
private static void appendTo(Queue queue, String s) {
if(!s.equals(leftChar) && !s.equals(rightChar)) {
queue.add(s);
}
}
/**
* 比较优先级
* @param start
* @param to
* @return
*/
private static int comparePriority(String start, String to) {
return operationSymbolMap.get(start).compareTo(operationSymbolMap.get(to));
}
public static void main(String[] args) {
// String[] pre = new String[]{"(","name = 'xmd'","and","age = 18",")","or","status = 1"};
// String[] pre = new String[]{"201","or","202","and","(","305","and","205",")",};
// (xzd_dzmc > '40' or xzd_dzmc < '30') and (sfzhm = '123123111155558856');
String[] pre = new String[]{"(","xzd_dzmc","or","xzd_dzmc","and","sfzhm",")","and","bcd"};
// String[] pre = new String[]{"(","xzd_dzmc","or","xzd_dzmc","and","sfzhm",")",};
// String[] pre = new String[]{"xzd_dzmc","and","xzd_dzmc","or","abc",};
// String[] pre = new String[]{"xzd_dzmc","or","xzd_dzmc","and","abc","or","bcd","and","cde"};
// String[] pre = new String[]{"xzd_dzmc","or","xzd_dzmc","and","sfzhm",};
StringBuilder sb = new StringBuilder();
for (int i = 0; i < pre.length; i++) {
sb.append(pre[i]);
}
System.out.println("前缀表达式:" + sb.toString());
Queue queue = new PreToAfterUtil().parsePre(pre);
System.out.println("后缀表达式:" + queue.toString());
}
}
修改的地方如下截图:
这里如果不做这个判断,就会导致原来栈中的关系条件直接出栈,然后在后缀式中出现关系条件缺少的问题,被注释的那一行一开始我没有注释,但是和注释了的结果没啥区别,因为此时的栈中结果没有栈元素了,所以去掉也不影响。
这里修改的原因是后缀式中随着添加括号的情况不同 括号有时会出现在后缀式中的问题。
然后测试了下多种加括号的情形,结果基本正确,如果有不正确的地方,希望能够给出指示,万分感谢!
在此再次感谢博主的链接给我带来的帮助:https://blog.51cto.com/11290909/2085571