import javax.script.*;
/**
* Sample class showing how to use the JavaScript ScriptEngine
* of Java 1.6 to evaluate mathematical expressions
*/
public class Evaluator
{
public static void main(String[] args) throws Exception
{
String input = "2*(3+1-2*4)+9";
System.out.println(input+" = "+evaluate(input));
input = "Math.pow(1+1, Math.sin(Math.PI / 6))";
System.out.println(input+" = "+evaluate(input));
input = "1+1";
System.out.println(input+" = "+evaluate(input));
// Invalid input
//input = "";
//input = "x+3";
//input = "4+3)";
//input = "/4+3";
//input = "1+1==2";
//System.out.println(input+" = "+evaluate(input));
}
/**
* Evaluates the mathematical expression in the given String
* using the JavaScript ScriptEngine. Thus, the given String
* must use JavaScript syntax. Valid strings may be <br />
* <b>2*(3+4)</b> <br />
* or
* <b>Math.pow(1+1, Math.sin(Math.PI / 6))</b> <br />
* <br />
* Throws an IllegalArgumentException if a parsing error occurs
*
* @param The string containing the expression to evaluate
* @return The result of evaluating the expression
* @throws IllegalArgumentException If the String can not be
* evaluated
*/
public static double evaluate(String string)
{
ScriptEngine engine =
new ScriptEngineManager().getEngineByName("JavaScript");
try
{
Object object = engine.eval("eval("+string+")");
if ((object != null) && (object instanceof Number))
{
return ((Number)(object)).doubleValue();
}
else
{
throw new IllegalArgumentException(
"Invalid input: '"+string+"'");
}
}
catch (ScriptException e)
{
throw new IllegalArgumentException(
"Invalid input: '"+string+"'", e);
}
}
}
|
Find ich cool ;)
Interessant finde ich auch wie ähnlich sich C# und Java sind. – gfoidl 20.09.09
|
||
|
für den Anfang sicherlich eine sinnvolle Methode
Dankeschön ;-) – clonejo 20.09.09
|
||
|
ein Problem habe ich allerdings noch: wenn ich das Ergebnis, wie von dir beschrieben zu Double casten lasse, sind Berechnungen wie "1+1" nicht möglich und werfen den Fehler, dass Integer nicht zu Double gecastet werden kann.
Wenn ich statt Double Integer verwende, gehen logischerweise keine Kommazahlen mehr. – clonejo 20.09.09
|
||
|
Das Problem mit dem 1+1 trat bei mir nicht auf - aber ich habe es mal editiert, um es "robuster" gegen Fehler zu machen, so dass keine ClassCastException oder NullPointerException mehr geworfen werden sollte.
Man könnte es noch erweitern: Z.B. wird "1+1==2" ja zu einem 'Boolean' ausgewertet, was für manche Anwendungen praktisch sein könnte. Aber es sollte in erster Linie ein Beispiel sein, wie man die ScriptEngine für solche Dinge verwenden kann - unabhängig davon, welche darüber hinaus gehenden Möglichkeiten die ScriptEngine bietet. – Marco13 20.09.09
|
||
|
Schöne Sache! ++rep
Ist das innere eval wirklich nötig? Die Expresion wird doch schon vorher ausgewertet. – Kambfhase 03.01.10
|
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class DynamicComputation {
public static void main(final String[] args) throws Exception {
final String test = "24/18*2+6";
final double retVal = doCompute(test);
System.out.println(retVal);
}
/**
* Kompiliere Javaklasse, die expression berechnet
*
* @param expression math. ausdruck
* @return Ergebnis
* @throws Exception kompilieren gescheitert, Kein temp. Verz. vorhanden,
* expression nicht zu parsen etc. etc.
*/
private static double doCompute(String expression) throws Exception {
// Javacode, der kompiliert wird
final String java = String.format(
"public class Compute {public static double doCompute() {return (double)%s;}}",
expression);
// temporäre Datei anlegen, um temp-Verzeichnis zu finden und gleich
// dafür sorgen, dass sie gelöscht wird
final File tmpFile = File.createTempFile("tmp", null);
tmpFile.deleteOnExit();
// temp verzeichnis - hier legen wir unsere Java-Datei ab und
// kompilieren später
final File tmpDir = tmpFile.getParentFile();
// Schreiben der Java-Datei
final File javaFile = new File(tmpDir, "Compute.java");
javaFile.deleteOnExit();
final BufferedWriter bWrit = new BufferedWriter(new FileWriter(javaFile));
bWrit.write(java);
bWrit.close();
// kompilieren
final JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
int ok = comp.run(null, System.out, System.err, javaFile.getAbsolutePath());
if (ok != 0) {
throw new RuntimeException(String.format("Cannot parse expression '%s'", expression));
}
// Das machen wir nur, um die kompilierte Datei wieder loszuwerden
final File classFile = new File(tmpDir, "Compute.class");
classFile.deleteOnExit();
// Jetzt laden wir die frisch kompilierte Klasse
final ClassLoader cld = new URLClassLoader(new URL[] { tmpDir.toURI().toURL() });
final Class clazz = Class.forName("Compute", true, cld);
// ... und führen die Berechnung durch
final Method method = clazz.getDeclaredMethod("doCompute");
return (Double) method.invoke(null);
}
}
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
public class DynamicComputationWithYahoo {
public static void main(final String[] args) throws Exception {
final String test = "24/18*2+6^5";
final double retVal = doCompute(test);
System.out.println(retVal);
}
/**
* Lass yahoo die Arbeit machen
*
* @param expression math. ausdruck
* @return Ergebnis
* @throws Exception keine verbindung, Ergebnis nicht zu parsen, HTML-Code
* geändert, expression nicht zu parsen etc. etc.
*/
private static double doCompute(final String expression) throws Exception {
// wenn nötig, proxy setzen
System.getProperties().put("proxySet", "true");
System.getProperties().put("proxyPort", "8080");
System.getProperties().put("proxyHost", "irgendein.proxy");
// erst mal leerzeichen loswerden
final String tmpExpr = expression.replaceAll("\\s", "");
// wir schicken die anfrage an yahoo
final String urlStr = String.format(
"http://de.search.yahoo.com/search?p=%s&fr=yfp-t-501&ei=UTF-8&rd=r1", URLEncoder
.encode(tmpExpr, "UTF-8"));
final URL url = new URL(urlStr);
final BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
// ... und suchen in der Response nach dem Ergebnis
try {
String line = null;
while ((line = in.readLine()) != null) {
line = line.replaceAll("\\s", "");
if (line.contains(tmpExpr + "=")) {
int begIdx = line.indexOf("=", line.indexOf(tmpExpr));
int endIdx = line.indexOf("<", line.indexOf(tmpExpr));
return Double.parseDouble(line.substring(begIdx + 1, endIdx).trim().replaceAll(
",", "."));
}
}
} finally {
in.close();
}
throw new RuntimeException(String.format("Cannot parse expression '%s'", expression));
}
}