前段時間,在瀏覽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("\n");
- }
- 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);
- }