翻译逻辑表达式
自定义逻辑表达式,关键字:= 等于,& 与,| 或, !非, ( , ) ,<> 包含,>< 不包含, # 不等于。
表达式支持括号标识作用域。
自动机分析如下:
JAVA 实现:
public class ConditionAnalysis2 { // 终止符号 Set<Character> signSet; ConditionAnalysis2() { this.signSet = new HashSet<Character>(); signSet.add(' '); signSet.add('='); signSet.add('('); signSet.add(')'); signSet.add('#'); signSet.add('<'); signSet.add('>'); signSet.add('&'); signSet.add('|'); }public boolean analysis(String expression) { if (null == expression || expression.length() == 0) return false; if (expression.charAt(0) != '(') expression = "(" + expression + ")"; Res res = this.getRes(expression, 0, new Context(ContextStatus.START), false); return res.res; } private Res getRes(String expression, int left, Context context, boolean isOppo) { int len = expression.length(), right = left; while (right < len) { char c = expression.charAt(right); if (c == ' ') { right++; continue; } // 回归 if (')' == c) { if (isOppo) context.currentRes = !context.currentRes; Res res = new Res(context.currentRes, left, right + 1); System.out.println(expression.substring(isOppo ? left - 2 : left - 1, right + 1) + " : " + res.res); return res; } // 递归 if (c == '(' || (c == '!' && right + 1 < len && expression.charAt(right + 1) == '(')) { Res partRes = null; if (c == '(') partRes = this.getRes(expression, right + 1, new Context(ContextStatus.WAIT_RES), false); else partRes = this.getRes(expression, right + 2, new Context(ContextStatus.WAIT_RES), true); if (null == partRes) throw new RuntimeException("error at " + right); if (null == context.currentRes) context.currentRes = partRes.res; else { if (context.contextStatus == ContextStatus.AND) { context.currentRes = context.currentRes & partRes.res; } else if (context.contextStatus == ContextStatus.OR) { context.currentRes = context.currentRes | partRes.res; } } context.contextStatus = ContextStatus.RES; right = partRes.right; continue; } // 顺序 if (c == '&') { context.contextStatus = ContextStatus.AND; right++; continue; } if (c == '|') { context.contextStatus = ContextStatus.OR; right++; continue; } Res partRes = this.getPartRes(expression, right); if (context.contextStatus == ContextStatus.WAIT_RES) { context.currentRes = partRes.res; } else if (context.contextStatus == ContextStatus.AND) { context.currentRes = context.currentRes & partRes.res; } else if (context.contextStatus == ContextStatus.OR) { context.currentRes = context.currentRes | partRes.res; } context.contextStatus = ContextStatus.RES; right = partRes.right; } if (isOppo) context.currentRes = !context.currentRes; return new Res(context.currentRes, left, right); } private Res getPartRes(String expression, int left) { int len = expression.length(), right = left; Context currentContext = new Context(ContextStatus.WAIT_TOKEN); Token leftToken = null; boolean isOppo = false; Res res = null; while (right < len) { char c = expression.charAt(right); if (c == ' ') { right++; continue; } if (c == '!') { if (currentContext.contextStatus == ContextStatus.WAIT_TOKEN || currentContext.contextStatus == ContextStatus.WAIT_OPPO2) { currentContext.contextStatus = ContextStatus.WAIT_OPPO2; isOppo = !isOppo; right++; continue; } throw new RuntimeException("error ! at " + right); } if (c == '=' || c == '#' || c == '<' || c == '>') { if (c == '=') currentContext.contextStatus = ContextStatus.EQ; else if (c == '#') currentContext.contextStatus = ContextStatus.NOT_EQ; else if (c == '<' && currentContext.contextStatus == ContextStatus.TOKEN) currentContext.contextStatus = ContextStatus.XYW; else if (c == '<' && currentContext.contextStatus == ContextStatus.DYW) currentContext.contextStatus = ContextStatus.NOT_CON; else if (c == '>' && currentContext.contextStatus == ContextStatus.TOKEN) currentContext.contextStatus = ContextStatus.DYW; else if (c == '>' && currentContext.contextStatus == ContextStatus.XYW) currentContext.contextStatus = ContextStatus.CON; right++; continue; } Token token = this.getToken(expression, right); if (currentContext.contextStatus == ContextStatus.WAIT_TOKEN || currentContext.contextStatus == ContextStatus.WAIT_OPPO2) { leftToken = token; currentContext.contextStatus = ContextStatus.TOKEN; right = token.right; continue; } else { Boolean currentRes = null; if (currentContext.contextStatus == ContextStatus.EQ) { currentRes = token.token.equals(leftToken.token); } else if (currentContext.contextStatus == ContextStatus.NOT_EQ) { currentRes = !token.token.equals(leftToken.token); } else if (currentContext.contextStatus == ContextStatus.CON) { currentRes = leftToken.token.contains(token.token); } else if (currentContext.contextStatus == ContextStatus.NOT_CON) { currentRes = !leftToken.token.contains(token.token); } else if (currentContext.contextStatus == ContextStatus.XYW) { currentRes = Long.valueOf(leftToken.token) < Long.valueOf(token.token); } else if (currentContext.contextStatus == ContextStatus.DYW) { currentRes = Long.valueOf(leftToken.token) > Long.valueOf(token.token); } if (null == currentRes) throw new RuntimeException("res is null! error at " + right); right = token.right; if (isOppo) currentRes = !currentRes; res = new Res(currentRes, left, right); break; } } System.out.println(" " + expression.substring(left, right) + " : " + res.res); return res; } private Token getToken(String expression, int left) { int len = expression.length(), right = left; char c = expression.charAt(right); StringBuilder stringBuilder = new StringBuilder(); while (right < len && !this.signSet.contains(c)) { stringBuilder.append(expression.charAt(right)); right++; if (right < len) c = expression.charAt(right); } return new Token(stringBuilder.toString(), left, right); } class Res { Boolean res; int left, right; public Res(Boolean res, int left, int right) { this.res = res; this.left = left; this.right = right; } } class Token { String token; int left; int right; Token(String token, int left, int right) { this.token = token; this.left = left; this.right = right; } } class Context { ContextStatus contextStatus; Boolean currentRes; Context(ContextStatus contextStatus) { this.contextStatus = contextStatus; } } public enum ContextStatus { // 外层状态 START, WAIT_OPPO, WAIT_OPPO2, WAIT_RES, WAIT_RES2, RES, AND, OR, DONE, // 内层状态 WAIT_TOKEN, TOKEN, EQ, NOT_EQ, XYW, DYW, CON, NOT_CON } }
JS实现:
function ConditionAnalysis() { this.termSet = new Set(); this.termSet.add('='); this.termSet.add('('); this.termSet.add(')'); this.termSet.add('#'); this.termSet.add('>'); this.termSet.add('<'); this.termSet.add('&'); this.termSet.add('|'); this.analysis = function (expression) { if (!expression || expression.length == 0) return false; if (expression.charAt(0) != "(") expression = "(" + expression + ")"; return this.getRes(expression, 0, "START", false); } this.getRes = function (expression, left, currentStatus, isOppo) { let len = expression.length, right = left, currentRes = null; while (right < len) { let c = expression.charAt(right); if (c == " ") { right++; continue; } if (c == ")") { if (currentRes === null) throw "currentRes is null! " + left + "," + right; if (isOppo) currentRes = !currentRes; console.log(expression.substring(isOppo ? left - 2 : left - 1, right + 1) + " : " + currentRes); return {data: currentRes, left, right}; } if (c == "&") { if (currentStatus == "RES") { currentStatus = "AND"; right++; continue; } throw "error & at " + right; } if (c == "|") { if (currentStatus == "RES") { currentStatus = "OR"; right++; continue; } throw "error | at " + right; } if (c == "(" || (c == "!" && right + 1 < len && expression.charAt(right + 1) == "(")) { let partRes = this.getRes(expression, c == "!" ? right + 2 : right + 1, "WAIT_RES", c == "!" ? true : false); if (currentStatus == "START" || currentStatus == "WAIT_RES") currentRes = partRes.data; else if (currentStatus == "AND") currentRes = currentRes && partRes.data; else if (currentStatus == "OR") currentRes = currentRes || partRes.data; else throw "error at " + right + " , " + currentStatus; currentStatus = "RES"; right = partRes.right + 1; continue; } let partRes = this.getPartRes(expression, right, "WAIT_TOKEN"); if (currentStatus == "WAIT_RES") currentRes = partRes.data; else if (currentStatus == "AND") currentRes = currentRes && partRes.data; else if (currentStatus == "OR") currentRes = currentRes || partRes.data; else throw "error at " + right; currentStatus = "RES"; right = partRes.right; } return {data: currentRes, left, right}; } this.getPartRes = function (expression, left, currentStatus) { let len = expression.length, right = left, isOppo = false, leftToken = null; let res = null; while (right < len) { let c = expression.charAt(right); if (c == " " || c == "!" || c == "=" || c == "#" || c == "<" || c == ">") { if (c == "!") { if (currentStatus == "WAIT_TOKEN" || currentStatus == "WAIT_OPPO") { currentStatus = "WAIT_OPPO"; isOppo = !isOppo; } } else if (c == "=") { if (currentStatus != "TOKEN") throw "error = at " + right; currentStatus = "EQ"; } else if (c == "#") { if (currentStatus != "TOKEN") throw "error = at " + right; currentStatus = "NOT_EQ"; } else if (c == "<") { if (currentStatus == "TOKEN") currentStatus = "XYW"; else if (currentStatus == "DYW") currentStatus = "NOT_CON"; else throw "error < at " + right; } else if (c == ">") { if (currentStatus == "XYW") currentStatus = "CON"; else if (currentStatus == "TOKEN") currentStatus = "DYW"; else throw "error > at " + right; } right++; continue; } let token = this.getToken(expression, right); right = token.right; if (currentStatus == "WAIT_TOKEN" || currentStatus == "WAIT_OPPO") { leftToken = token; currentStatus = "TOKEN"; } else if (currentStatus == "EQ") { res = leftToken.data == token.data; break; } else if (currentStatus == "NOT_EQ") { res = leftToken.data != token.data; break; } else if (currentStatus == "XYW") { res = leftToken.data < token.data; break; } else if (currentStatus == "DYW") { res = leftToken.data > token.data; break; } else if (currentStatus == "CON") { let currRes = false, array = this.strToArray(leftToken.data); for (let j = 0; j < array.length; j++) { if (array[j] == token.data) { currRes = true; break; } } res = currRes; break; } else if (currentStatus == "NOT_CON") { let currRes = true, array = this.strToArray(leftToken.data); for (let j = 0; j < array.length; j++) { if (array[j] == token.data) { currRes = false; break; } } res = currRes; break; } } if (res == null) throw "getPartRes error: " + left + "," + right + ":" + expression.substring(left.right); if (isOppo) res = !res; console.log(" " + expression.substring(left, right) + " : " + res); return {data: res, left, right} } this.getToken = function (expression, left) { let len = expression.length, right = left, c = expression.charAt(right); let data = ""; while (right < len && !this.termSet.has(c)) { data += c; right++; if (right < len) c = expression.charAt(right); } return {data, left, right}; } this.strToArray = function (str) { if (!str || str.length == 0) return []; if (str.charAt(0) == "[") str = str.substring(1, str.length - 1); let array = str.split(","); return array; } } /* 测试样例 * 1=1 true * !1=1 false * 1=2 false * !1=2 true * 1>2 false * 1<2 true * [1,2,3,4,5]<>6 true * [1,2,3,4,5]><6 false * [1,2,3,4,5]<>1 false * [1,2,3,4,5]><1 true * 1#1 false * 1#3 true * 1=1&1=2 false * 1=1&2=2 true * 1=1|1=2 true * 1=3|1=2 false * 1=1&(1=2|1#1) false * !1=1&(1=2|1#1) false * !(1=1&(1=2|1#1)) true * 1=1&(1=2|1=1) true * (( 1 = 1 & ( 2 = 1 | 2 = 6))&[1,2,3,4,5]><5) false * ((1=2&(2=2|2=6))&[1,2,3,4,5]><5) false * (((1=1)|(1=2))&2=1|1=1) true * (((1=1)|(1=2))&(2=1&1=1)) false * !(((1=1)|(1=2))&(2=1&1=1)) true * (((1=1)|(1=2))&!(2=1&1=1)) true */ let expression = "((1=2&(2=2|2=6))&[1,2,3,4,5]><5)"; let analysis = new ConditionAnalysis(); let res = analysis.analysis(expression); console.log(res);
当你看清人们的真相,于是你知道了,你可以忍受孤独