java代碼執(zhí)行字符串中的邏輯運(yùn)算方法
方式一
public class Test
{
public static void main(String[] args) throws Exception {
String str = "(a or b) and c";
str = str.replaceAll("or", "||");
str = str.replaceAll("and", "&&");
System.out.println(str);
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
engine.put("a",true);
engine.put("b",false);
engine.put("c",true);
Object result = engine.eval_r(str);
System.out.println("結(jié)果類型:" + result.getClass().getName() + ",計算結(jié)果:" + result);
}
}
這種方式使用js的方式進(jìn)行運(yùn)算,使用較簡單,但是當(dāng)運(yùn)算double類型的四則運(yùn)算時結(jié)果會出現(xiàn)循環(huán)小數(shù),運(yùn)算結(jié)果會出現(xiàn)問題.
方式二(能夠保證四則運(yùn)算精度):
/**
* @Project: BizRule
* @File: org.coffeesweet.util.MathExpress.java
* @Author: coffeesweet
* @Date: 2011-3-28
* @Description: 2011 coffeesweet Inc. All rights reserved.
*/
package org.coffeesweet.util;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author coffeesweet
* +,-,*,/四則運(yùn)算的表達(dá)式逆波蘭解析計算類,精確計算,應(yīng)用BigDecimal類處理
* 支持負(fù)數(shù),但規(guī)范除整個表達(dá)式第一個數(shù)為負(fù)數(shù)時可以不出現(xiàn)在'('后,其它表達(dá)式中間任何位置的
* 負(fù)數(shù)必須出現(xiàn)在'('后,即:用括號括起來。比如:-3+(-2+1)*10或-3+((-2)+1)*10或(-3)+(-2+1)*10或(-3)+((-2)+1)*10
*/
public class MathExpress {
/**
* +
*/
private final static String OP1 = "+";
/**
* -
*/
private final static String OP2 = "-";
/**
* *
*/
private final static String OP3 = "*";
/**
* /
*/
private final static String OP4 = "/";
/**
* ^
*/
// private final static String OP5 = "^";
/**
* %
*/
// private final static String OP6 = "%";
/**
* (
*/
private final static String OPSTART = "(";
/**
* )
*/
private final static String OPEND = ")";
/**
* !用來替代負(fù)數(shù)前面的'-'
*/
// private final static String NEGATIVESING = "!";
/**
* !用來替代負(fù)數(shù)前面的'+'
*/
// private final static String PLUSSING = "@";
/**
* '#'用來代表運(yùn)算級別最低的特殊字符
*/
// private final static String LOWESTSING = "#";
//最原始的四則運(yùn)算式
private String expBase;
//經(jīng)過初始化處理后的四則運(yùn)算式
private String expInited;
//精度
private int precision=10;
//取舍模式
private RoundingMode roundingMode=RoundingMode.HALF_UP;
//精度上下文
private MathContext mc;
//四則運(yùn)算解析
private List<String> expList = new ArrayList<String>();
//存放逆波蘭表達(dá)式
private List<String> rpnList = new ArrayList<String>();
public MathExpress(){
}
public MathExpress(String expBase) {
init(expBase,this.precision,this.roundingMode);
}
public MathExpress(String expBase,int precision,RoundingMode roundingMode){
init(expBase,precision,roundingMode);
}
public void init(String expBase,int precision,RoundingMode roundingMode){
this.expBase = expBase;
this.precision = precision;
this.roundingMode = roundingMode;
this.mc = new MathContext(precision,roundingMode);
this.expInited = initExpress(expBase);
StringTokenizer st = new StringTokenizer(this.expInited,"+-*/^%()",true);
while(st.hasMoreElements()){
this.expList.add(st.nextElement().toString().trim());
}
this.rpnList = initRPN(this.expList);
}
/**
* @return the expBase
*/
public String getExpBase() {
return expBase;
}
/**
* @param expBase the expBase to set
*/
public void setExpBase(String expBase) {
this.expBase = expBase;
}
/**
* @return the expInited
*/
public String getExpInited() {
return expInited;
}
/**
* @param expInited the expInited to set
*/
public void setExpInited(String expInited) {
this.expInited = expInited;
}
/**
* @return the precision
*/
public int getPrecision() {
return precision;
}
/**
* @param precision the precision to set
*/
public void setPrecision(int precision) {
this.precision = precision;
}
/**
* @return the roundingMode
*/
public RoundingMode getRoundingMode() {
return roundingMode;
}
/**
* @param roundingMode the roundingMode to set
*/
public void setRoundingMode(RoundingMode roundingMode) {
this.roundingMode = roundingMode;
}
/**
* @return the expList
*/
public List<String> getExpList() {
return expList;
}
/**
* @param expList the expList to set
*/
public void setExpList(List<String> expList) {
this.expList = expList;
}
/**
* @return the rpnList
*/
public List<String> getRpnList() {
return rpnList;
}
/**
* @param rpnList the rpnList to set
*/
public void setRpnList(List<String> rpnList) {
this.rpnList = rpnList;
}
/**
* @return the mc
*/
public MathContext getMc() {
return mc;
}
/**
* @param mc the mc to set
*/
public void setMc(MathContext mc) {
this.mc = mc;
}
/**
* 去除空白字符和在負(fù)號'-'前加'0',便于后面的StringTokenizer
* @param exp
* @return
*/
private static String initExpress(String exp){
String reStr = null;
reStr = exp.replaceAll("\\s", "");
if(reStr.startsWith("-")){
reStr = "0"+reStr;
}
reStr = reStr.replaceAll("\\(\\-", "(0-");
return reStr;
}
/**
* 是否是整數(shù)或是浮點(diǎn)數(shù),但默認(rèn)-05.15這種也認(rèn)為是正確的格式
* @param str
* @return
*/
private boolean isNumber(String str){
Pattern p = Pattern.compile("^(-?\\d+)(\\.\\d+)?$");
Matcher m = p.matcher(str);
boolean isNumber = m.matches();
return isNumber;
}
/**
* 設(shè)置優(yōu)先級順序()設(shè)置與否無所謂
* @param sign
* @return
*/
private int precedence(String str){
char sign = str.charAt(0);
switch(sign){
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
case '%':
return 3;
case '(':
case ')':
// case '#':
default:
return 0;
}
}
/**
* 轉(zhuǎn)變?yōu)槟娌ㄌm表達(dá)式
* @param strList
* @return
*/
public List<String> initRPN(List<String> strList){
List<String> returnList = new ArrayList<String>();
//用來存放操作符的棧
Stack stack = new Stack();
// stack.push(LOWESTSING);
int length = strList.size();
for(int i=0;i<length;i++ ){
String str = strList.get(i);
if(isNumber(str)){
returnList.add(str);
}else{
if(str.equals(OPSTART)){
//'('直接入棧
stack.push(str);
}else if(str.equals(OPEND)){
//')'
//進(jìn)行出棧操作,直到棧為空或者遇到第一個左括號
while (!stack.isEmpty()) {
//將棧頂字符串做出棧操作
String tempC = stack.pop();
if (!tempC.equals(OPSTART)) {
//如果不是左括號,則將字符串直接放到逆波蘭鏈表的最后
returnList.add(tempC);
}else{
//如果是左括號,退出循環(huán)操作
break;
}
}
}else{
if (stack.isEmpty()) {
//如果棧內(nèi)為空
//將當(dāng)前字符串直接壓棧
stack.push(str);
}else{
//棧不空,比較運(yùn)算符優(yōu)先級順序
if(precedence(stack.top())>=precedence(str)){
//如果棧頂元素優(yōu)先級大于當(dāng)前元素優(yōu)先級則
while(!stack.isEmpty() && precedence(stack.top())>=precedence(str)){
returnList.add(stack.pop());
}
}
stack.push(str);
}
}
}
}
//如果棧不為空,則將棧中所有元素出棧放到逆波蘭鏈表的最后
while (!stack.isEmpty()) {
returnList.add(stack.pop());
}
return returnList;
}
/**
* 計算逆波蘭表達(dá)式
* @param rpnList
* @return
*/
public String caculate(List<String> rpnList){
Stack numberStack = new Stack();
int length=rpnList.size();
for(int i=0;i<length;i++){
String temp=rpnList.get(i);
if(isNumber(temp)){
numberStack.push(temp);
}else{
BigDecimal tempNumber1 = new BigDecimal(numberStack.pop(),this.mc);
BigDecimal tempNumber2 = new BigDecimal(numberStack.pop(),this.mc);
BigDecimal tempNumber = new BigDecimal("0",this.mc);
if(temp.equals(OP1)){
tempNumber=tempNumber2.add(tempNumber1);
}else if(temp.equals(OP2)){
tempNumber=tempNumber2.subtract(tempNumber1);
}else if(temp.equals(OP3)){
tempNumber=tempNumber2.multiply(tempNumber1);
}else if(temp.equals(OP4)){
tempNumber=tempNumber2.divide(tempNumber1,
precision,
roundingMode);
}
numberStack.push(tempNumber.toString());
}
}
return numberStack.pop();
}
/**
* 按照類的缺省參數(shù)進(jìn)行計算
* @return
*/
public String caculate(){
return caculate(this.rpnList);
}
/**
* 數(shù)字條件表達(dá)式精確比較
* eg: "3.0>2" "1<5" "1==5" "1!=5" "(1.0+2)>3" "((-0.9+3)>=2. 1)"
* 不支持&&,||等連接符
* @param str
* @return
*/
public static boolean compareTo(String strParm){
boolean reBoolean = false;
boolean isParentheses = false;//標(biāo)記是否有()括上整個字符串
String str = initExpress(strParm);
Pattern p = Pattern.compile("^\\([\\s\\S]*\\)$");
Matcher m = p.matcher(str);
isParentheses = m.matches();
if(-1==str.indexOf(">=")&&-1==str.indexOf("<=")&&-1==str.indexOf("==")&&-1==str.indexOf("!=")){
if(-1==str.indexOf(">")&&-1==str.indexOf("<"))
throw new IllegalArgumentException("異常:條件表達(dá)式不正確!");
}
if(-1 != str.indexOf(">=")){
String[] strTemps = str.split(">=");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( -1 == r ){
reBoolean = false;
}else{
reBoolean = true;
}
}else if(-1 != str.indexOf("<=")){
String[] strTemps = str.split("<=");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( 1 == r ){
reBoolean = false;
}else{
reBoolean = true;
}
}else if(-1 != str.indexOf("==")){
String[] strTemps = str.split("==");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( 0 == r ){
reBoolean = true;
}else{
reBoolean = false;
}
}else if(-1 != str.indexOf("!=")){
String[] strTemps = str.split("!=");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( 0 != r ){
reBoolean = true;
}else{
reBoolean = false;
}
}else if((-1 != str.indexOf(">")) && (-1 == str.indexOf("="))){
String[] strTemps = str.split(">");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( 1 == r ){
reBoolean = true;
}else{
reBoolean = false;
}
}else if((-1 != str.indexOf("<")) && (-1 == str.indexOf("="))){
String[] strTemps = str.split("<");
if(isParentheses){
strTemps[0] = strTemps[0] + ")";
strTemps[1] = "(" + strTemps[1];
}
int r = new BigDecimal((new MathExpress(strTemps[0]).caculate())).compareTo(new BigDecimal((new MathExpress(strTemps[1]).caculate())));
if( -1 == r ){
reBoolean = true;
}else{
reBoolean = false;
}
}
return reBoolean;
}
public static void main(String...args){
// MathExpress me = new MathExpress("-(-0.5+0.1)*10+2",10,RoundingMode.HALF_UP);
// System.out.println(me.getExpList());
// List<String> tempList = me.initRPN(me.getExpList());
// System.out.println(tempList);
// String resultStr = me.caculate(tempList);
// System.out.println(resultStr);
MathExpress me = new MathExpress("-(-1.5000000003+0.1)*10+2");
String resultStr = me.caculate();
BigDecimal bd = new BigDecimal(resultStr);
BigDecimal bd2 = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println(me.caculate());
System.out.println(bd.toString());
System.out.println(bd.scale());
System.out.println(bd2.toString());
System.out.println(bd2.scale());
// System.out.println("------------------------------------");
// Pattern p = Pattern.compile("^\\([\\s\\S]*\\)$");//匹配類似以'('開頭')'結(jié)尾的字符串
// Matcher m = p.matcher("(2. 0>2.22)");
// System.out.println(m.matches());
boolean reBoolean = MathExpress.compareTo("((-8.0+3)>=2. 1)");
System.out.println(reBoolean);
}
/**
* 棧
*/
private class Stack {
LinkedList<String> stackList = new LinkedList<String>();
public Stack() {
}
/**
* 入棧
* @param expression
*/
public void push(String expression) {
stackList.addLast(expression);
}
/**
* 出棧
* @return
*/
public String pop() {
return stackList.removeLast();
}
/**
* 棧頂元素
* @return
*/
public String top() {
return stackList.getLast();
}
/**
* 棧是否為空
* @return
*/
public boolean isEmpty() {
return stackList.isEmpty();
}
}
}
以上這篇java代碼執(zhí)行字符串中的邏輯運(yùn)算方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于Java實(shí)現(xiàn)一個復(fù)雜關(guān)系表達(dá)式過濾器
這篇文章主要為大家詳細(xì)介紹了如何基于Java實(shí)現(xiàn)一個復(fù)雜關(guān)系表達(dá)式過濾器。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-07-07
詳解Java?ReentrantLock可重入,可打斷,鎖超時的實(shí)現(xiàn)原理
前面講解了ReentrantLock加鎖和解鎖的原理實(shí)現(xiàn),但是沒有闡述它的可重入、可打斷以及超時獲取鎖失敗的原理,本文就重點(diǎn)講解這三種情況,需要的可以了解一下2022-10-10
Java中Elasticsearch 實(shí)現(xiàn)分頁方式(三種方式)
Elasticsearch是用Java語言開發(fā)的,并作為Apache許可條款下的開放源碼發(fā)布,是一種流行的企業(yè)級搜索引擎,這篇文章主要介紹了Elasticsearch實(shí)現(xiàn)分頁的3種方式,需要的朋友可以參考下2022-07-07
詳解如何配置springboot跳轉(zhuǎn)html頁面
這篇文章主要介紹了詳解如何配置springboot跳轉(zhuǎn)html頁面,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java創(chuàng)建excel示例(jxl使用方法)
Java Excel是一開放源碼項(xiàng)目,通過它Java開發(fā)人員可以讀取Excel文件的內(nèi)容、創(chuàng)建新的Excel文件、更新 已經(jīng)存在的Excel文件。下面是使用方法,包括去掉網(wǎng)格線、字體設(shè)置、單元格設(shè)置、對齊方式等設(shè)置2014-03-03
Java toString方法重寫工具之ToStringBuilder案例詳解
這篇文章主要介紹了Java toString方法重寫工具之ToStringBuilder案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

