(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的剖析. ...
随机推荐
- 计算机丨浏览器访问出现DNS_PROBE_POSSIBLE解决方法
方法1.打开命令控制台输入: netsh winsock reset.提示重启,电脑重启后就ok了. 其他方法待续......
- codeforces 553A A. Kyoya and Colored Balls(组合数学+dp)
题目链接: A. Kyoya and Colored Balls time limit per test 2 seconds memory limit per test 256 megabytes i ...
- hdu-5867 Water problem(水题)
题目链接: Water problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- Linux下用FFMPEG采集usb摄像头到RTMP
Linux下用 FFMPEG 采集 usb摄像头视频 和 摄像头内置麦克风音频 到RTMP服务 ffmpeg -f video4linux2 -qscale 10 -r 12 -s 640x480 ...
- @@cursor_rows变量解析
刚刚看了@@curosr_rows这个全局变量,发现这个变量挺有意思.要懂得这个变量的意义,基本上牵扯到cursor一些比较容易忽视的内容. @@cursor_rows是用来记录当前游标的数量,也就从 ...
- AngularJS方法 —— angular.copy
描述: 复制一个对象或者一个数组(好吧,万物皆对象,数组也是一个对象). 如果省略了destination,一个新的对象或数组将会被创建出来: 如果提供了destination,则source对象中的 ...
- Java中的String数据类型
本文主要是说明一些String数据类型的基本知识,有些杂乱,不过都是比较重要的东西,主要是参考了网上人的资料.原文网址:http://dev.yesky.com/91/2309091.shtml 主要 ...
- nginx实现防盗链配置方法介绍
有些朋友觉得防盗链就是防止图片,其实有很多东西要进行防盗链了,下面我来介绍在nginx中实现防盗链配置方法有对图片防盗链与下载资源等. 防盗链配置 假设网站域名是 www.php100.com. 编辑 ...
- RSA-CRT leaks__因使用中国余数定理计算RSA所引起的私钥泄露
在heartbleed[1]漏洞后,很多用户打开了PFS[2]功能.但很不幸,之后RedHat又报告出在多个平台上存在RSA-CRT导致的密钥泄露[3]. 中国余数定理(CRT)常被用在RSA的计算中 ...
- TModJS:README
ylbtech-TModJS:README 1.返回顶部 1. TmodJS 项目已经停止维护,请使用更好的代替方案:art-template-loader TmodJS(原名 atc)是一个简单易用 ...