2

I have a string with math operators which I need to turn into an int (the answer).

The below code does not work, but I'm not sure how I can get the answer variable to work.

String question;
int answer;

question = "7/7+9-9*5/5";
answer = Integer.parseInt(question);
Kristian Matthews
  • 800
  • 3
  • 14
  • 28
  • @Photon I want the computed result. – Kristian Matthews Mar 02 '13 at 11:37
  • thats too easy follow others answers – Trikaldarshiii Mar 02 '13 at 11:38
  • 1
    If you are learning how computation is done than go with reverse polish notation, if you are just interessted in the result than go with Scriptengine – A4L Mar 02 '13 at 11:39
  • @A4L I'm only interested in the result at this point, but I don't believe the Android SDK natively supports ScriptEngine. – Kristian Matthews Mar 02 '13 at 11:45
  • @Kristian Matthews, take a look a this question http://stackoverflow.com/questions/10704885/evaluate-mathematical-expression-within-string ... i'am afraid you'll have to find some 3rd party api or do it programing the algorithms yourself – A4L Mar 02 '13 at 11:52
  • @A4L Thank for your help, I think I'll have to rethink the whole solution to generate the question/answer variables. Can't use their party APIs unfortunately. – Kristian Matthews Mar 02 '13 at 11:57

5 Answers5

3

Integer.parseInt(question); ... If only it was so simple ...

You have there a mathematical expression "7/7+9-9*5/5" in infix notation which you want to evalutate and print the result to the user. The way to do that is to convert it to postfix notation also known as Reverse Polish notation using the Shunting-yard algorithm. Once you have converted the expression to postfix evaluating is pretty easy using this algorithm

A4L
  • 17,353
  • 6
  • 49
  • 70
3

1. Javascript Engine

public class MainTest {
    public static void main(String[] args)throws Exception {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("js");
        Object result = engine.eval("7/7+9-9*5/5");
        System.out.println(result);
    }
}

2. Java Compiler

a) Compile string into Java class

b) Load the class using a custom ClassLoader.

c) Excute it using reflect.

Here's a sample:

import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;


public class MainTest{
    public static void eval(String str) throws Exception{
        StringBuffer sb = new StringBuffer();
        sb.append("public class TempClass{\n");
        sb.append("    public void run(){\n");
        sb.append("        " + str + "\n");
        sb.append("    }\n");
        sb.append("}\n");
        System.out.println(sb.toString());
        Class clazz = new EvalClassLoader().findClass(sb.toString());

        Method method = clazz.getMethod("run");
        method.invoke(clazz.newInstance());
    }

    public static void main(String[] args) throws Exception {
        eval("System.out.println(7/7+9-9*5/5);");
    }
}

/**
 * A custom class Loader.
 */
class EvalClassLoader extends ClassLoader{
    private String tempCLassName = "TempClass";
    @Override
    protected Class<?> findClass(String codeStr) throws ClassNotFoundException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        JavaFileObject file = new ClassFromString(tempCLassName, codeStr.toString());

        // Start a compile task
        Iterable<JavaFileObject> compilationUnits = Arrays.asList(file);
        JavaCompiler.CompilationTask task = compiler
                    .getTask(null, null, null, null, null, compilationUnits);
        if(task.call()){
            return loadClass(tempCLassName);
        }
        return null;
    }

}

/**
 * A Java class constructed from String.
 */
class ClassFromString extends SimpleJavaFileObject{
    private String code;

    public ClassFromString(String className,String code){
        super(URI.create("string:///" + className.replace('.', '/') +
                Kind.SOURCE.extension), Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors)
            throws IOException {
        return code;
    }

}
WoooHaaaa
  • 19,732
  • 32
  • 90
  • 138
2

Since 1.6 Java has embedded JavaScript engine

    ScriptEngine e = new ScriptEngineManager().getEngineByName("js");
    int res = ((Number)e.eval("7/7+9-9*5/5")).intValue();
Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
1

You need something like Reverse Polish notation. This should take about one day to understand and port the algorithm to Java. Absolutely you can do a Google search for code, but I would highly recommend learning that wiki page.

0

I would let the framework and other libraries do the work for me. In case this is an academical thing, I would suggest going with the solution provided by Lai Vung. Use the ScriptManager that will do the parsing and calculating for you, then convert the output to the needed type. Quick demo:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Main {
    public static void main(String[] args) throws ScriptException {
        String question;
        int answer;

        question = "7/7+9-9*5/5";

        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine engine = mgr.getEngineByName("JavaScript");

        answer = ((Number)engine.eval(question)).intValue();
       }
}

Worth being mentioned: if android does not offer support for the Script engine probably you have to add the ScriptEngine library to your path. A good post explaining how to use Android and Rhino can be found here.

Community
  • 1
  • 1
Olimpiu POP
  • 5,001
  • 4
  • 34
  • 49