(JAVA)String型別的邏輯語句編譯
專案中遇到了動態配置條件觸發相應事件的需求,需要根據String型別的邏輯語句,以及動態獲取的資料,計算資料對應的結果,java實現。解決思路及程式碼實現如下,有需要的同學請自取。
一、需求提取
根據需求,拋開業務部分,我們可以將需求簡化成以下核心邏輯。輸入String型別的邏輯字串,支援的邏輯符號包括 > , < , <= ,>= ,== ,() 。 例如: "(a>1&&b<2)||(c>=3&&d==4)" ,動態解析該字串,並對輸入的任意json類資料做出正確的邏輯判斷。如{“b” : 10 , "a" : 9 , "c":"error" }。
二、設計思路
因為每一個最小的邏輯點。如 “a>1” 都只有兩個結果:成功或者失敗,並且成功或者失敗後,往往需要執行下一個邏輯,所以該邏輯模型可以轉換成一個二叉樹的結構。據此我們先畫出 "(a>1&&b<2)||(c>=3&&d==4)" 的邏輯圖
每一個邏輯根據成功或者失敗,指向了另外的邏輯,或者指向了最終結果,這裡我們可以把指向的這個操作等價成指標,該指標指向了另外一個邏輯實體,或者指向了最終結果,又因為java中的指標,或者說引用都是需要事先指定資料型別的,如果我們使用邏輯實體和布林型別的兩種資料物件,那我們就只能將引用宣告為兩種資料物件的統一父類Object。但是因為Object在使用過程中涉及到了型別的判斷及轉化,很不方便,所以我們直接使用邏輯實體表示 邏輯,用 null表示可以直接返回最終結果。
除了兩個引用以外,該邏輯實體應該還包括三個關鍵字,三個關鍵字有資料對應的key值"a" , 資料對應的邏輯符號 “>”,資料對應的閾值"1"。
據此,我們可以確定該邏輯實體的五個欄位 ,建出以下實體
1 public class Logic { 2 //值對應的key值 3 private String key; 4 //邏輯符號 包括 > < >= <= == 5 private double symbol; 6 //閾值 7 private double value; 8 //成功是返回,為null時表示最終結果為true 9 private Logic sucLogic; 10 //失敗是返回,為null時表示最終結果為false 11 private Logic failLogic; 12 13 //後面會用到的兩個方法 14 //在logic樹的每一層失敗分支子樹上都加一個成功時呼叫的物件 15 public void setSucLogicEveryFail(Logic logic){ 16 Logic logic1 = this; 17 while (true){ 18 logic1.setSucLogic( logic ); 19 if ( logic1.getFailLogic != null ){ 20 logic1 = logic1.getFailLogic(); 21 }else { 22 return; 23 } 24 } 25 } 26 //在logic樹的每一層成功分支上子樹上都加一個失敗時呼叫的物件 27 public void setFailLogicEverySuc(Logic logic){ 28 Logic logic1 = this; 29 while (true){ 30 logic1.setFailLogic( logic ); 31 if ( logic1.getSucLogic != null ){ 32 logic1 = logic1.getSucLogic (); 33 }else { 34 return; 35 } 36 } 37 } 38 }
使用該實體的原因如下:
1) 可以很清楚的表明邏輯關係
2) 增加了處理時的開銷,減少了使用時的開銷,更好的支援大批量的資料判斷
三、編碼實現
1. 根據string生成Logic物件的程式碼
1 public class CreateLogic { 2 3 private static String[] symbol = {">=","<=",">","<","=="}; 4 private static String[] backSymbol = {"<=",">=","<",">","=="}; 5 6 public static void main(String[] args) { 7 CreateLogic createLogic = new CreateLogic(); 8 Logic logic = createLogic.handleContentLogic("(a>1&&b<2)||(c>=3&&d==4)"); 9 System.out.println( logic); 10 } 11 12 private Logic handleContentLogic(String content) { 13 //1.去除掉首位的無效括號 14 content = this.removeNoUseContent( content ); 15 //2.將content拆成小的邏輯塊。 16 List<String> blockContents = new ArrayList<>(); 17 int point = 0; 18 int flag = 0; 19 for (int i = 0; i < content.length(); i++) { 20 char c = content.charAt(i); 21 if( '(' == c){ 22 flag++; 23 continue; 24 }else if( ')' == c){ 25 flag--; 26 if( flag == 0 ){ 27 blockContents.add( content.substring( point , i + 1) ); 28 point = i + 1; 29 } 30 }else if( flag == 0 && ('|' == content.charAt(i) || '&' == content.charAt(i)) ){ 31 if( i - point > 1){ 32 blockContents.add( content.substring( point , i ) ); 33 point = i; 34 } 35 }else if( i == content.length() - 1){ 36 blockContents.add( content.substring( point , i + 1 ) ); 37 } 38 } 39 //3.遍歷獲取最終邏輯 40 Logic logic = null; 41 for (int i = 0; i < blockContents.size(); i++) { 42 String blockContent = blockContents.get(i); 43 if( blockContent.startsWith("||(") ){ 44 Logic logic1 = this.handleContentLogic(blockContent.substring(2)); 45 logic.setFailLogicEverySuc(logic1); 46 }else if( blockContent.startsWith("&&(") ){ 47 Logic logic1 = this.handleContentLogic(blockContent.substring(2)); 48 logic.setSucLogicEveryFail(logic1); 49 }else if( blockContent.startsWith("&&") ) { 50 Logic logic1 = this.getLogicBySimpleContent(blockContent.substring(2)); 51 logic1.setSucLogicEveryFail(logic); 52 logic = logic1; 53 }else if( blockContent.startsWith("||") ) { 54 Logic logic1 = this.getLogicBySimpleContent(blockContent.substring(2)); 55 logic1.setFailLogicEverySuc(logic); 56 logic = logic1; 57 }else { 58 logic = this.getLogicBySimpleContent(blockContent); 59 } 60 } 61 return logic; 62 } 63 64 /** 65 * 去除掉首位的無效括號 66 * @param content 67 * @return 68 */ 69 public String removeNoUseContent( String content ){ 70 List<String> list = new ArrayList<>(Arrays.asList(content.split(""))) ; 71 //1.首位的小括號為無效的小括號,先去除掉 72 int flag1 = 0; 73 int flag2 = 0; 74 while (true){ 75 if( "(".equals(list.get(0) )){ 76 flag1++; 77 list.remove(0); 78 }else { 79 break; 80 } 81 } 82 if( flag1 > 0 ){ 83 for (int i = 0; i < list.size(); i++) { 84 if( flag1 == 0 ){ 85 break; 86 } 87 if( "(".equals(list.get(i) ) ){ 88 flag2++; 89 }else if( ")".equals( list.get(i) ) ){ 90 if(flag2 > 0){ 91 flag2--; 92 continue; 93 }else { 94 flag1--; 95 list.remove(i); 96 i--; 97 } 98 } 99 } 100 } 101 return StringUtils.join(list.toArray()); 102 } 103 104 /** 105 * 簡單的邏輯文字直接轉換成一個邏輯實體 106 * @param blockContent 107 * @return 108 */ 109 private Logic getLogicBySimpleContent(String blockContent) { 110 Logic logic = new Logic(); 111 for (int i = 0; i < symbol.length; i++) { 112 if( blockContent.indexOf( symbol[i] ) != -1 ){ 113 String value1 = blockContent.substring(0 , blockContent.indexOf( symbol[i] )); 114 String value2 = blockContent.substring( blockContent.indexOf( symbol[i] ) + symbol[i].length()); 115 try { 116 double b = Double.valueOf(value2); 117 logic.setKey(value1); 118 logic.setValue(b); 119 logic.setSymbol(symbol[i]); 120 }catch (Exception e){ 121 double b = Double.valueOf(value1); 122 logic.setKey(value2); 123 logic.setValue(b); 124 logic.setSymbol(backSymbol[i]); 125 } 126 return logic; 127 } 128 } 129 return logic; 130 } 131 }
2. 根據Logic和json判斷最終結果
1 public class HandleLogic { 2 /** 3 * 根據邏輯樹,遞迴獲取最終的邏輯結果s 4 */ 5 public boolean handleMessageByLogicCore(Logic logic , JSONObject object ) { 6 boolean bool = false; 7 String key = logic.getKey(); 8 if( object.get(key) == null ){ 9 return this.getLogicByResult(logic , bool , object); 10 } 11 double value = logic.getValue(); 12 double realValue = object.getDoubleValue( key ); 13 switch ( logic.getSymbol() ){ 14 case ">=": 15 bool = realValue >= value; 16 break; 17 case "<=": 18 bool = realValue <= value; 19 break; 20 case "==": 21 bool = realValue == value; 22 break; 23 case "<": 24 bool = realValue < value; 25 break; 26 case ">": 27 bool = realValue > value; 28 break; 29 } 30 return this.getLogicByResult(logic , bool , object); 31 } 32 33 /** 34 * 根據邏輯的結果,獲取邏輯的成功/失敗的子邏輯樹,不存在則直接返回成功/失敗 35 * @param logic 當前邏輯樹 36 * @param b 當前邏輯樹的執行結果 37 * @param object 當前邏輯樹的處理物件 38 * @return 39 */ 40 private boolean getLogicByResult(Logic logic, boolean b, JSONObject object) { 41 if( b ){ 42 if( logic.getSucLogic() == null ){ 43 return true; 44 }else { 45 return handleMessageByLogicCore( logic.getSucLogic() , object ); 46 } 47 }else { 48 if( logic.getFailLogic() == null ){ 49 return false; 50 }else { 51 return handleMessageByLogicCore( logic.getFailLogic() , object ); 52 } 53 } 54 } 55 }
以上就是邏輯語句編譯的總結,原創不易,轉載請註明出