(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"。
据此,我们可以确定该逻辑实体的五个字段 ,建出以下实体
public class Logic {
//值对应的key值
private String key;
//逻辑符号 包括 > < >= <= ==
private double symbol;
//阈值
private double value;
//成功是返回,为null时表示最终结果为true
private Logic sucLogic;
//失败是返回,为null时表示最终结果为false
private Logic failLogic; //后面会用到的两个方法
//在logic树的每一层失败分支子树上都加一个成功时调用的对象
public void setSucLogicEveryFail(Logic logic){
Logic logic1 = this;
while (true){
logic1.setSucLogic( logic );
if ( logic1.getFailLogic != null ){
logic1 = logic1.getFailLogic();
}else {
return;
}
}
}
//在logic树的每一层成功分支上子树上都加一个失败时调用的对象
public void setFailLogicEverySuc(Logic logic){
Logic logic1 = this;
while (true){
logic1.setFailLogic( logic );
if ( logic1.getSucLogic != null ){
logic1 = logic1.getSucLogic ();
}else {
return;
}
}
}
}
使用该实体的原因如下:
1) 可以很清楚的表明逻辑关系
2) 增加了处理时的开销,减少了使用时的开销,更好的支持大批量的数据判断
三、编码实现
1. 根据string生成Logic对象的代码
public class CreateLogic { private static String[] symbol = {">=","<=",">","<","=="};
private static String[] backSymbol = {"<=",">=","<",">","=="}; public static void main(String[] args) {
CreateLogic createLogic = new CreateLogic();
Logic logic = createLogic.handleContentLogic("(a>1&&b<2)||(c>=3&&d==4)");
System.out.println( logic);
} private Logic handleContentLogic(String content) {
//1.去除掉首位的无效括号
content = this.removeNoUseContent( content );
//2.将content拆成小的逻辑块。
List<String> blockContents = new ArrayList<>();
int point = 0;
int flag = 0;
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if( '(' == c){
flag++;
continue;
}else if( ')' == c){
flag--;
if( flag == 0 ){
blockContents.add( content.substring( point , i + 1) );
point = i + 1;
}
}else if( flag == 0 && ('|' == content.charAt(i) || '&' == content.charAt(i)) ){
if( i - point > 1){
blockContents.add( content.substring( point , i ) );
point = i;
}
}else if( i == content.length() - 1){
blockContents.add( content.substring( point , i + 1 ) );
}
}
//3.遍历获取最终逻辑
Logic logic = null;
for (int i = 0; i < blockContents.size(); i++) {
String blockContent = blockContents.get(i);
if( blockContent.startsWith("||(") ){
Logic logic1 = this.handleContentLogic(blockContent.substring(2));
logic.setFailLogicEverySuc(logic1);
}else if( blockContent.startsWith("&&(") ){
Logic logic1 = this.handleContentLogic(blockContent.substring(2));
logic.setSucLogicEveryFail(logic1);
}else if( blockContent.startsWith("&&") ) {
Logic logic1 = this.getLogicBySimpleContent(blockContent.substring(2));
logic1.setSucLogicEveryFail(logic);
logic = logic1;
}else if( blockContent.startsWith("||") ) {
Logic logic1 = this.getLogicBySimpleContent(blockContent.substring(2));
logic1.setFailLogicEverySuc(logic);
logic = logic1;
}else {
logic = this.getLogicBySimpleContent(blockContent);
}
}
return logic;
} /**
* 去除掉首位的无效括号
* @param content
* @return
*/
public String removeNoUseContent( String content ){
List<String> list = new ArrayList<>(Arrays.asList(content.split(""))) ;
//1.首位的小括号为无效的小括号,先去除掉
int flag1 = 0;
int flag2 = 0;
while (true){
if( "(".equals(list.get(0) )){
flag1++;
list.remove(0);
}else {
break;
}
}
if( flag1 > 0 ){
for (int i = 0; i < list.size(); i++) {
if( flag1 == 0 ){
break;
}
if( "(".equals(list.get(i) ) ){
flag2++;
}else if( ")".equals( list.get(i) ) ){
if(flag2 > 0){
flag2--;
continue;
}else {
flag1--;
list.remove(i);
i--;
}
}
}
}
return StringUtils.join(list.toArray());
} /**
* 简单的逻辑文本直接转换成一个逻辑实体
* @param blockContent
* @return
*/
private Logic getLogicBySimpleContent(String blockContent) {
Logic logic = new Logic();
for (int i = 0; i < symbol.length; i++) {
if( blockContent.indexOf( symbol[i] ) != -1 ){
String value1 = blockContent.substring(0 , blockContent.indexOf( symbol[i] ));
String value2 = blockContent.substring( blockContent.indexOf( symbol[i] ) + symbol[i].length());
try {
double b = Double.valueOf(value2);
logic.setKey(value1);
logic.setValue(b);
logic.setSymbol(symbol[i]);
}catch (Exception e){
double b = Double.valueOf(value1);
logic.setKey(value2);
logic.setValue(b);
logic.setSymbol(backSymbol[i]);
}
return logic;
}
}
return logic;
}
}
2. 根据Logic和json判断最终结果
public class HandleLogic {
/**
* 根据逻辑树,递归获取最终的逻辑结果s
*/
public boolean handleMessageByLogicCore(Logic logic , JSONObject object ) {
boolean bool = false;
String key = logic.getKey();
if( object.get(key) == null ){
return this.getLogicByResult(logic , bool , object);
}
double value = logic.getValue();
double realValue = object.getDoubleValue( key );
switch ( logic.getSymbol() ){
case ">=":
bool = realValue >= value;
break;
case "<=":
bool = realValue <= value;
break;
case "==":
bool = realValue == value;
break;
case "<":
bool = realValue < value;
break;
case ">":
bool = realValue > value;
break;
}
return this.getLogicByResult(logic , bool , object);
} /**
* 根据逻辑的结果,获取逻辑的成功/失败的子逻辑树,不存在则直接返回成功/失败
* @param logic 当前逻辑树
* @param b 当前逻辑树的执行结果
* @param object 当前逻辑树的处理对象
* @return
*/
private boolean getLogicByResult(Logic logic, boolean b, JSONObject object) {
if( b ){
if( logic.getSucLogic() == null ){
return true;
}else {
return handleMessageByLogicCore( logic.getSucLogic() , object );
}
}else {
if( logic.getFailLogic() == null ){
return false;
}else {
return handleMessageByLogicCore( logic.getFailLogic() , object );
}
}
}
}
以上就是逻辑语句编译的总结,原创不易,转载请注明出处。
(JAVA)String类型的逻辑语句编译的更多相关文章
- java string类型的初始化
以下基本上是java string类型最常用的三种方法 new string()就不介绍了 基本等同于第三种 String a; 申明一个string类型的 a,即没有在申请内存地址,更没有在内存 ...
- Java——string类型与date类型之间的转化
String类型转化为Date类型 方法一 Date date=new Date("2019-01-25"); 方法二 String =(new SimpleDateFormat( ...
- JAVA String类型和原型模式
如上例所述,变量a,b和它们的值10,20都是存在栈里面,声明的所以String类型的引用也都是存在栈里.而字符串abc是存在字符串常量池中,new出来的String对象则是存在堆里. String ...
- Java String类型数据的字节长度
问题描述: 向Oracle数据库中一varchar2(64)类型字段中插入一条String类型数据,程序使用String.length()来进行数据的长度校验,如果数据是纯英文,没有问题,但是如果数据 ...
- JAVA String类型的一些小操作
String类型是否包含某个String类型的函数:源字符串.contains(包含字符串) 返回值为:boolean类型(true或false) String类型把某个字符替换成另一个字符:源字符 ...
- java String 类型总结
java中String是个对象,是引用类型?,基础类型与引用类型的区别是,基础类型只表示简单的字符或数字,引用类型可以是任何复杂的数据结构,基本类型仅表示简单的数据类型,引用类型可以表示复杂的数据类型 ...
- 为什么说Java String 类型的值是不可改变的?
String对象是不可变的,它的内容是不能改变的.下列代码会改变字符串的内容吗? 1 2 String s = "Java"; s = "HTML"; 答案是不 ...
- java String类型转 java.sql.time类型
String[] timePhase = reservationRuleInDTO.getTimePhase().split(",");List<ReservationTim ...
- Java String的相关性质分析
引言 String可以说是在Java开发中必不可缺的一种类,String容易忽略的细节也很多,对String的了解程度也反映了一个Java程序员的基本功.下面就由一个面试题来引出对String的剖析. ...
随机推荐
- Python编程-一个小爬虫工具的实现过程
需求描述: 1,打开网站: 2,获取网站的文件内容: 3,返回保存到文件中: 这里的就用到了多线程的方法 import requests,threading,time def write_html(u ...
- Idea_学习_03_IDEA中使自定义类型的文件进行代码高亮识别
如果你只是想用xml的编辑模式来编辑*.screen文件的话,可以在 Settings->Editor->File Types 中,在Recognized File Types选中XML, ...
- PS 滤镜——(扭曲)逆球面化 (凹陷效果)
%%% Inverse_Spherize %%% 逆球面化 clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image Proce ...
- FEC之我见四
接上文,来详细的说明一下FEC前向纠错的具体实现: FEC_matrix是一个比较常用的算法,Vandermonde,范德蒙矩阵是法国数学家范德蒙提出的一种各列为几何级数的矩阵. 范德蒙矩阵的定义: ...
- What is Photon Server?
http://blog.csdn.net/menuconfig/article/details/8215033 Photon Server是一套套裝的遊戲伺服器,以往開發線上遊戲都必需自行花費大筆的研 ...
- 标准模板库(STL)学习指南之List链表
本文转载自天极网,原文地址:http://www.yesky.com/255/1910755.shtml.转载请注明 什么是STL呢?STL就是Standard Template Library,标准 ...
- FIS 雪碧图sprite合并
1 安装fis(必须先安装node和npm):npm install -g fis3 2 构建项目发布到根目录下的output:fis3 release -d ./output 项目根目录:FIS3 ...
- spring初始化顺序
首先,Spring bean的默认加载顺序是怎么控制的 工程中有2个bean,A和B,其中必须先初始化A再初始化B,但是没有depend-on或者Order等方式去保证,只不过恰好刚好这么运行着没出事 ...
- TS学习之接口
TypeScript的核心原则之一是对值所具有的结构进行类型检查.接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约. interface testType { name: string; ...
- 7.JasperReports学习笔记7-applet打印
转自:http://www.blogjava.net/vjame/archive/2013/10/12/404908.html 打包applet的class和所需的jar包,并加上数字签名 要运行打印 ...