前段时间,在浏览javaeye论坛,看见有人征集如何在java中运行数学表达式。 结果方案五花八门: 1.jakarta commons JEXL. 2.Beanshell 3.Java Math Expression Parser jep 4.parse combinator jparsec 5.jdk 6.0的 script 6.利用SQL 7.自己写语法分析 如果自己写语法分析,没有个2000行估计搞不定。有人用sql来运行数学表达式,比较另类。 不过由于前段时间较深入的学习了一些java的javascript引擎,我给出的方案就是用javascript来计算了。 java中比较著名的js引擎当属mozilla开源的rhino,不过jdk6已经把它收归帐下,成了正规军。
public
class
MathEval
...
{ public static void main(String[] args) ... { Context cx = Context.enter(); try ... { Scriptable scope = cx.initStandardObjects(); String str = " 9*(1+2) " ; Object result = cx.evaluateString(scope, str, null , 1 , null ); double res = Context.toNumber(result); System.out.println(res); } finally ... { Context.exit(); } } }
下面总结一下前段时间学习rhino的心得(给自己的程序添加脚本功能,其实是很酷的):
一:环境配置及运行js脚本: 在 http://www.mozilla.org/rhino/ 下载rhino: 把js.jar加入系统CLASSPATH中 可以以交互模式调用js解释器: java org.mozilla.javascript.tools.shell.Main 然后您应该会看到解释器的版本号,后面跟着提示符 js> 用法如下: 比如:有一个js文件: D:/eclipse-workshop/rhinoExample/src/isPrime.js 内容如下:
function
isPrime (num)
...
{ if (num <= 1 ) ... { print( " Please enter a positive integer >= 2. " ) return false } var prime = true var sqrRoot = Math.round(Math.sqrt(num)) for ( var n = 2 ; prime & n <= sqrRoot; ++ n) ... { prime = (num % n != 0 ) } return prime }
如何运行呢: 1:在命令行下键入: java org.mozilla.javascript.tools.shell.Main 2:在js〉下键入: load("D:/eclipse-workshop/rhinoExample/src/isPrime.js"); 注意:是“/”而不是“/” 3:键入: isPrime(77); 可看见返回结果为false。 键入: isPrime(71);返回true
再给个例子,脚本如下:
person
=
...
{ name: " Mike Squillace " , age: 37 , position: " software engineer " , getFirstName: function () ... { return this .name.split( " " )[ 0 ]} }
person.getFirstName()
js产生swing的例子: load("D:/eclipse-workshop/rhinoExample/src/SwingApplication.js"); 怎么样?看见效果没?是不是很强悍?其中SwingApplication.js是rhnio自带的例子。
Rhino还有一个js脚本的调试器: Rhino JavaScript Debugger: java org.mozilla.javascript.tools.debugger.Main [options] [filename.js] [script-arguments]
只须运行java org.mozilla.javascript.tools.debugger.Main,就可以看到调试器的界面了。
为了加快js文件运行的速度,可以把它编译为class文件: compile: java org.mozilla.javascript.tools.jsc.Main D:/eclipse-workshop/rhinoExample/src/FirstCompile.js 编译产生FirstCompile.class文件 在D:/eclipse-workshop/rhinoExample/src/下运行该class文件: java FirstCompile
二:在实际应用中不可避免的需要遇到java代码如何和javascript脚本相互访问的问题: 这是一个最简单的例子:(liveConnect.js是rhnio自带的例子): load("D:/eclipse-workshop/rhinoExample/src/liveConnect.js");
在给个复杂点的例子, 没有什么逻辑,纯技术展示,呵呵: JSFunction.java:
package
co.test;
import
org.mozilla.javascript.Function;
public
class
JSFunction
//
extends ScriptableObject
...
{ private String name; private Function handle; public void setHandler(Function func) ... { this .handle = func; } public Function getHandler() ... { return this .handle; } public JSFunction(String s) ... { this .name = s; } public static void print(String s) ... { System.out.println(s); } public String getName() ... { return name; } public void setName(String name) ... { this .name = name; } }
JSExploration.java:
package co.test; import java.io.FileReader; import java.io.LineNumberReader; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.Scriptable; public class JSExploration
...
{ private Context cx; private Scriptable scope; public JSExploration() ... { this .cx = Context.enter(); this .scope = cx.initStandardObjects(); } public Object runJavaScript(String filename) ... { String jsContent = this .getJsContent(filename); Object result = cx.evaluateString(scope, jsContent, filename, 1 , null ); return result; } private String getJsContent(String filename) ... { LineNumberReader reader; try ... { reader = new LineNumberReader( new FileReader(filename)); String s = null ; StringBuffer sb = new StringBuffer(); while ((s = reader.readLine()) != null ) ... { sb.append(s).append( " " ); } return sb.toString(); } catch (Exception e) ... { // TODO Auto-generated catch block e.printStackTrace(); return null ; } } public Scriptable getScope() ... { return scope; } public static void main(String[] args) ... { String filename = System.getProperty( " user.dir " ) + " /jsmap.js " ; JSExploration jsExploration = new JSExploration(); Object result = jsExploration.runJavaScript(filename); Scriptable scope = jsExploration.getScope(); Scriptable obj = (Scriptable) scope.get( " obj " , scope); System.out.println( " obj.a == " + obj.get( " a " , obj)); Scriptable b = (Scriptable) obj.get( " b " , obj); System.out.println( " b[0] == " + b.get( 0 , b)); Boolean flag = (Boolean) scope.get( " flag " , scope); System.out.println(flag); Scriptable myobj = (Scriptable) scope.get( " obj " , scope); Boolean myflag = (Boolean) scope.get( " flag " , scope); System.out.println(myflag); Scriptable jsFunction = (Scriptable) scope.get( " jsFunction " , scope); Function fc = (Function) jsFunction.get( " handler " , jsFunction); Object isPrime = fc.call(Context.getCurrentContext(), jsFunction, fc, new Object[] ... { " this is my test " } ); } }
js脚本:jsmap.js
var
swingNames
=
JavaImporter(); swingNames.importPackage(Packages.java.lang); swingNames.importPackage(Packages.co.test); obj
=
...
{a: 1 , b:[ ' x ' , ' y ' ]}
next
=
isPrime flag
=
isPrime(
5
)
with
(swingNames)
...
{ System.out.println( " in javascript " ); JSFunction.print( " in JSFunction " ); jsFunction = new JSFunction( " lichunlei " ); var name = jsFunction.getName(); System.out.println( " get name from java source: " + name); jsFunction.setHandler(log); }
java.lang.System.out.println(
"
not use swingNames
"
);
function
isPrime (num)
...
{ java.lang.System.out.println( " in isPrime(num) " ); if (num <= 1 ) ... { java.lang.System.out.println( " Please enter a positive integer >= 2. " ) return false } var prime = true var sqrRoot = Math.round(Math.sqrt(num)) for ( var n = 2 ; prime & n <= sqrRoot; ++ n) ... { prime = (num % n != 0 ) } return prime }
function
log(msg)
...
{ java.lang.System.out.println( " in function log: " + msg); }