| 

.NET C# Java Javascript Exception

1
Ich möchte mit Java einen komplexeren Term ausrechnen, den der Benutzer eingegeben hat.
z.B. "2*(3+1-2*4)+9"

Stellt Java eine Funktion dafür bereit? Oder gibt es gute Libraries dafür?
19.09.2009
clonejo 144 2 6
5 Antworten
7
Wenn es nicht zeitkritisch ist, und man Java 1.6 verwendet, kann man das auch von JavaScript ausrechnen lassen. Das ist sehr einfach zu verwenden, und hat den Vorteil, dass man keine zusätzlichen Bibliotheken benötigt.

Ein Beispiel:

EDITIERT - siehe Kommentar

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);
}
}
}
20.09.2009
Marco13 286 1 2
Marco13 286 1 2
Find ich cool ;)
Interessant finde ich auch wie ähnlich sich C# und Java sind.
gfoidl 20.09.2009
für den Anfang sicherlich eine sinnvolle Methode
Dankeschön ;-)
clonejo 20.09.2009
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.2009
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.2009
Schöne Sache! ++rep

Ist das innere eval wirklich nötig? Die Expresion wird doch schon vorher ausgewertet.
Kambfhase 03.01.2010
3
Dafür muss ein Parser für mathematische Formeln verwendet werden. ZB Jep Java - Math Expression Parser
19.09.2009
gfoidl 9,4k 3 5
2
Sicher auch nicht schneller, als die Javascript-Lösung und sicher auch mit krassen Sicherheitsrisiken behaftet, dafür aber echt cool ist die Möglichkeit, ab Java 6 das Compiler-API zu verwenden und eine Javaklasse zu kompilieren, die die Berechnung durchführt (der mathematische Ausdruck muss dabei genau wie bei der Javascript-Variante ein valides Java-Statement sein):

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);
}
}
23.09.2009
fenchurch 611 6
1
Du kannst ja mal meinen mathematischen Ausdrucks Parser ausprobieren, der sich an der Mathematica Syntax orientiert:



Javascript (oder andere Scriptingsprachen) würde ich z.B. in Servletanwendungen nicht benutzen, da durch einen Benutzer "eingebbare Scripts", zu Sicherheitsproblemen führen können.
21.09.2009
axelclk 21 1
1
Und noch einer - warum eigentlich nicht andere die Arbeit machen lassen ;-)

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));
}
}


Ich gebe aber gerne zu, dass das ziemlich wackelig ist :-)
23.09.2009
fenchurch 611 6

Stelle deine Java-Frage jetzt!