zoukankan      html  css  js  c++  java
  • (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 }

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

  • 相关阅读:
    【BZOJ4566】[HAOI2016]找相同字符
    【BZOJ3238】[AHOI2013]差异
    【BZOJ4698】[SDOI2008]Sandy的卡片
    后缀数组(SA)总结
    【HDU3117】Fibonacci Numbers
    线性常系数齐次递推总结
    【HDU4565】So Easy!
    【BZOJ3144】[HNOI2013]切糕
    【BZOJ1070】[SCOI2007]修车
    【LOJ6433】【PKUSC2018】最大前缀和
  • 原文地址:https://www.cnblogs.com/ttjsndx/p/10861612.html
Copyright © 2011-2022 走看看