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 }

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

  • 相关阅读:
    Nodejs下载和第一个Nodejs示例
    永久关闭Win10工具栏的TaskbarSearch控件
    对称加密,非对称加密,散列算法,签名算法
    【转】TTL和RS232之间的详细对比
    zlg核心板linux系统中查看系统内存等使用信息
    Power BI后台自动刷新数据报错 The operation was throttled by Power BI Premium because there were too many datasets being processed concurrently.
    剪切板和上传文件内容获取
    CSS, LESS, SCSS, SASS总结
    文字程序
    electron 打包“ERR_ELECTRON_BUILDER_CANNOT_EXECUTE”
  • 原文地址:https://www.cnblogs.com/ttjsndx/p/10861612.html
Copyright © 2011-2022 走看看