.NET C# Java Javascript Exception

 | 
Frage stellen Fragen Themen Mitglieder Abzeichen RSS-Feed
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.09
clonejo 134 1 5
Kommentieren - Für Rückfragen oder Anmerkungen
5 Antworten
6
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.09
Marco13 246 1 2
Marco13 246 1 2
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
3
Dafür muss ein Parser für mathematische Formeln verwendet werden. ZB Jep Java - Math Expression Parser
19.09.09
gfoidl 6,6k 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.09
fenchurch 521 3
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.09
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 :-)
Deine Antwort
Entweder einloggen... ...oder ohne Wartezeit registrieren
Name
Passwort
Passwort wiederholen
E-Mail
Geworben von


Login mit OpenID

Mit einem OpenID-Account kannst Du dich auf allen Webseiten anmelden, die OpenID unterstützen. Du hast bereits ein Benutzerkonto bei einem der folgenden Provider? Dann kannst Du dich direkt hier damit registrieren.


OpenID-Provider anklicken: