好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

利用ScriptEngineManager实现字符串公式灵活计算的方法

在开发中我们可能会遇到好多不固定的公式计算 如有时候我们需要将excel中大量的计算公式转换成java语言进行实现

如果说单纯的用java的基本方法实现计算 我们就需要的分析excel中的公式将其一一并转换成java代码 这样对我们开发人员来说工作量有点太大了 而且在转换过程中很可能会出错

下面就介绍一种简单的实现方法

我们知道js的eval()方法可以执行字符串的代码 而恰好jdk6增加了对脚本语言的支持 我们可以利用这个特性对计算实现简单化的处理

下面举个例子

加入有个公式

?

1

2

3

a+b*c

 

a= 1 ,b= 2 ,c= 3

我们可以将公式的a b c替换成数字 转换为 1+2*3 最后就可以得到结果了

接下来 我么就探讨下实现方法

直接以代吗的形式来写吧

?

1

2

3

4

5

6

7

8

9

10

11

12

public double calculation(string formula){

double result= null ; //计算结果

scriptenginemanager manager = new scriptenginemanager(); //创建一个scriptenginemanager对象

scriptengine engine = manager.getenginebyname( "js" ); //通过scriptenginemanager获得scriptengine对象

try {

result = ( double ) engine.eval(formula); //用scriptengine的eval方法执行脚本

} catch (scriptexception e) {

this .issuccess= false ;

result= double .nan;

}

return result;

}

利用上面的方法我们就可以将一个数学表达式计算出结果

calculation([1+2*3])-->得到结果7

显然这样是不能实现公式的灵活计算的 怎么实现a+b*c 此时我们应该会想到将参数abc替换成数字就可以实现计算结果了

接下来我们就探讨如何实现替换的功能

说到替换 我们不难想到string的replaceall方法,但是这样我们会遇到一个问题就是替换形如a+aa+aaa的问题

如果str.replaceall("a",2) ;结果就是2+22+222了

所以我想到了利用正则去准确匹配替换 方法如下

参数1:替换公式字的符串 参数2: 公式中要替换的字母如上边的a 参数3:要替换成的数值

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

/**

  * 精确替换字符 防止出现 匹配a 时将aa匹配的情况

  */

 

public static string replacestr(string sourcestr,string replacekey,string replacevalue){

string replacestrreg= "" ;

for ( char str_char:replacekey.tochararray()){

replacestrreg+= "[" ;

replacestrreg+=str_char;

replacestrreg+= "]" ;

}

string startreg= "^" +replacestrreg+ "([\\+\\-\\*/,)])" ;

string endreg= "([\\+\\-\\*/,(])" +replacestrreg+ "$" ;

string reg= "([^a-za-z])(" +replacestrreg+ ")" + "([^a-za-z])" ;

string endstr=sourcestr;

while (matchestr(endstr,replacekey)){

endstr=endstr.replaceall(startreg, replacevalue+ "$1" );

endstr=endstr.replaceall(reg, "$1" +replacevalue+ "$3" );

endstr=endstr.replaceall(endreg, "$1" +replacevalue);

}

return endstr;

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

/**

* 精确匹配字符 防止出现 匹配a 时将aa匹配的情况

*/

public static boolean matchestr(string sourcestr,string matchstr){

string replacestrreg= "" ;

for ( char str_char:matchstr.tochararray()){

replacestrreg+= "[" ;

replacestrreg+=str_char;

replacestrreg+= "]" ;

}

string startreg= "^" +replacestrreg+ "([\\+\\-\\*/,)])[\\s\\s]*" ;

string endreg= "[\\s\\s]*([\\+\\-\\*/,(])" +replacestrreg+ "$" ;

string reg= "[\\s\\s]*([^a-za-z])(" +replacestrreg+ ")" + "([^a-za-z])[\\s\\s]*" ;

if (sourcestr.matches(startreg)||sourcestr.matches(reg)||sourcestr.matches(endreg)){

return true ;

} else {

return false ;

}

}

上述的正则表达式就是利用了数学公式中出现+-*/运算符号的规律

这样我们就可以先替换 再计算了

我们的公式中可以实现计算平方等 如math.pow(2,2) 只要js支持的数学公式都可以写进去

至于怎么将公式中的参数全部替换 我们可以用循环遍历替换参数 这里就不写了 有了上面的方法就ok了

我有这样的想法就是因为开发中频繁编写公式 可能会出错 另一方面纯用java实现公式后期维护修改也麻烦 利用这种方法我们在后期修改公式时只需修改字符串公式即可

这样我们还可以让用户自定义公式

当然我们还可以利用scriptenginemanager他实现执行js代码块 如if语句等 下面是个例子 可以参考下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public map<string,object> myfunction(string formula){

scriptenginemanager manager = new scriptenginemanager();

scriptengine engine = manager.getenginebyname( "js" );

object result;

try {

engine.eval(formula);

invocable inv = (invocable) engine;

result=inv.invokefunction( "js" );

object function = engine.get( "usefunction" );

map.put( "result" , result);

map.put( "function" , function);

} catch (exception e) {

result= double .nan;

}

return map;

}

以上这篇利用scriptenginemanager实现字符串公式灵活计算的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/wyzdeng/article/details/78704256

查看更多关于利用ScriptEngineManager实现字符串公式灵活计算的方法的详细内容...

  阅读:47次