(JAVA)String类型的逻辑语句编译

Posted ttjsndx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(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 }

  以上就是逻辑语句编译的总结,原创不易,转载请注明出处。

以上是关于(JAVA)String类型的逻辑语句编译的主要内容,如果未能解决你的问题,请参考以下文章

switch语句(下)(转载)

java的结构和方法

Java连载18-引用数据类型三元运算符控制语句if

使用 Java 8 日期作为逻辑类型的 Avro

Java方法

js隐式类型转换,预编译递归