如何从String中获取数据

时间:2013-09-26 21:40:45

标签: java string parsing math

我正在编写一个计算器,当用户点击进入时,我需要它来查找例如括号的任何地方。

然后我需要计算器来解决第一个内部的数学问题。

在括号内部获取函数并将第二个String的值设置为括号内的任何内容的最佳方法是什么?

5 个答案:

答案 0 :(得分:3)

您可以使用堆栈:

  1. 将字符推送到堆栈,直到)
  2. 然后让你的子方程从堆栈中弹出,直到(
  3. 将等式的结果从步骤2推送到堆栈
  4. 重复直到找不到括号,然后求解最终方程式

答案 1 :(得分:1)

您有一些不同的方法来解决这个问题,

  1. 定义一个全局变量,当用户将其中一个操作数(+, - ,* /)保存在define变量中时。
  2. 拆分字符串,如果你把整个输入视为一个字符串,你可以用一个定义的操作数(+, - ,* /)拆分它,然后你有一个运算符和操作数的数组。
  3. 使用正则表达式,您可以使用正则表达式找出运算符和操作数。

答案 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();
  }