我正在编写一个计算器,当用户点击进入时,我需要它来查找例如括号的任何地方。
然后我需要计算器来解决第一个内部的数学问题。
在括号内部获取函数并将第二个String
的值设置为括号内的任何内容的最佳方法是什么?
答案 0 :(得分:3)
您可以使用堆栈:
)
(
答案 1 :(得分:1)
您有一些不同的方法来解决这个问题,
答案 2 :(得分:1)
作为替代方案,您可以让Java自行编译。它仅限于+ - / *
完整的工作示例:
import java.lang.*;
import java.io.*;
public class SO {
public static void main(String[] args) {
try { System.out.println(calculate("5 * (1 + 1)")); }
catch (Exception e) { System.out.println("we tried " + e); }
}
private static String subProc(String command) throws Exception {
Process proc = Runtime.getRuntime().exec(command); // kick off sub process
BufferedReader stdout = new BufferedReader(new
InputStreamReader(proc.getInputStream())); // read from stdout
StringBuilder sb = new StringBuilder(); // build output
String ln = stdout.readLine(); // read lines, until we are at the end
while (ln != null) { sb.append(ln); ln = stdout.readLine(); }
proc.waitFor(); // wait for process to exit
int exitCode = proc.exitValue(); // get exit code
if (exitCode != 0) // if it isn't 0, something went wrong. Throw error
throw new Exception("invalid math! exited with code: " + exitCode);
return sb.toString(); // return stdout
}
private static String calculate(String math) throws Exception {
//** Compile a new Java class that will spit out the calculation
File file = File.createTempFile("tmp", ".java"); // create new temp file
String classpath = file.getParent(), // get class path, and name
classname = file.getName().substring(0, file.getName().length() - 5);
PrintWriter writer = new PrintWriter(file); // write Java to temp file
writer.println(
"public class " + classname + "{" +
"public static void main(String[] args) { " +
"System.out.println(" + math + "); }}"); writer.close();
subProc("javac " + file.getAbsolutePath()); // compile it
file.delete(); // remove our source file
return subProc("java -cp " + classpath + " " + classname); // run it
}
}
像往常一样编译并运行:
javac SO.java; java SO
在此特定示例中,它将打印10
,因为调用是calculate("5 * (1 + 1)"));
这不是一个快速实现问题的实用方法,但它是一个纯粹的Java解决方案,我很开心。
答案 3 :(得分:0)
我喜欢前两张海报的想法,所以这是我的方法:
1)将字符放入堆栈。当您看到)
时,您会将成员从堆栈中弹出,直到看到(
。完成后,弹出所有字符并以相反的顺序将它们放入另一个String或StringBuffer或StringBuilder中。
2)通过反向优先分割等式的其余部分。然后,对于每个更高级别的运算符优先级,您可以通过该运算符拆分子方程。
3)然后,当你处于最高级别(例如指数)时,你就可以解决所有这些问题。然后进入较低级别的运营商。
答案 4 :(得分:0)
这是Wikipedia page on recursive descent parsers上语法子集的递归下降解析器,似乎与您的案例相关。
我没有包含一个tokenizer,但编写一个适合该接口的应该是相当简单的。代码与维基百科页面上的代码没有显着差异,只有实现语法的子集,并且实际执行计算。
/**
* From http://en.wikipedia.org/wiki/Recursive_descent_parser
*
* expression =
* [ "+" | "-" ] term { ("+" | "-") term } .
*
* term =
* factor { ( "*" | "/" ) factor } .
*
* factor =
* number
* | "(" expression ")" .
*/
public class Arithmetic
{
private final TokenStream tokenStream;
private TokenStream.Token currentToken;
private double currentValue;
public Arithmetic(TokenStream tokenStream) {
this.tokenStream = tokenStream;
}
public double parse() {
nextToken();
return expression();
}
private double expression() {
double lhs = 0.0;
if (accept(TokenStream.Token.MINUS)) {
lhs = -term();
} else {
// Optional unary plus swallowed
accept(TokenStream.Token.PLUS);
lhs = term();
}
for (boolean moreTerms = true; moreTerms; ) {
if (accept(TokenStream.Token.PLUS)) {
lhs += term();
} else if (accept(TokenStream.Token.MINUS)) {
lhs -= term();
} else {
moreTerms = false;
}
}
return lhs;
}
private double term() {
double lhs = factor();
for (boolean moreFactors = true; moreFactors; ) {
if (accept(TokenStream.Token.TIMES)) {
lhs *= factor();
} else if (accept(TokenStream.Token.DIVIDED_BY)) {
lhs /= factor();
} else {
moreFactors = false;
}
}
return lhs;
}
private double factor() {
if (peek(TokenStream.Token.NUMBER)) {
// Save currentValue before calling nextToken()
double value = currentValue;
nextToken();
return value;
}
require(TokenStream.Token.OPEN);
double value = expression();
require(TokenStream.Token.CLOSE);
return value;
}
private void nextToken() {
currentToken = tokenStream.nextToken();
if (currentToken == TokenStream.Token.NUMBER) {
currentValue = tokenStream.getValue();
}
}
private boolean peek(TokenStream.Token token) {
return (currentToken == token);
}
private boolean accept(TokenStream.Token token) {
if (peek(token)) {
nextToken();
return true;
}
return false;
}
private void require(TokenStream.Token token) {
if (currentToken == token) {
nextToken();
} else {
throw new IllegalStateException("Unexpected token " + currentToken);
}
}
}
Tokenizer
的界面非常简单:
public interface Tokenizer {
public enum Token {
// Terminals
PLUS,
MINUS,
TIMES,
DIVIDED_BY,
OPEN,
CLOSE,
NUMBER,
EOF
}
Token nextToken();
// Retrieve value when nextToken() returns NUMBER
double getValue();
}
另一种可能性是使用脚本工具来评估一些JavaScript,如下所示:
try
{
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
Object result = engine.eval("1 + 2 / 2");
System.out.println(result.getClass().getCanonicalName());
System.out.println(result);
}
catch (ScriptException e)
{
e.printStackTrace();
}