简体   繁体   English

使用Java的递归表达式求值程序

[英]Recursive expression evaluator using Java

I am going to write an expression evaluator which only does addition and subtraction. 我将编写一个表达式求值程序,它只进行加法和减法。 I have a simple algorithm to do that; 我有一个简单的算法来做到这一点; but, I have some implementation problems. 但是,我有一些实施问题。

I considered an expression as (it is a String) 我认为表达式为(它是一个字符串)

"(" <expression1> <operator> <expression2> ")"

Here is my algorithm 这是我的算法

String evaluate( String expression )

   if expression is digit
      return expression

   else if expression is "(" <expression1> <operator> <expression2> ")"
      cut the brackets out of it
      expression1 = evaluate( <expression1> )
      operator = <operator>
      expression2 = evaluate( <expression2> )

   if operator is +
      expression1 + expression2

   else if operator is -
      expression1 - expression2 

My problem is parsing <expression1> , <operator> and <expression2> from the expression. 我的问题是从<expression1>解析<expression1><operator><expression2> How can I do that? 我怎样才能做到这一点?

Note: I'm not asking for a code. 注意:我不是要求代码。 All I need is an idea to do that. 我需要的只是一个想法。

Thank you, 谢谢,

-Ali -Ali

My problem is parsing <expression1>, <operator> and <expression2> from the expression 我的问题是从表达式解析<expression1>,<operator>和<expression2>

Don't do that, then :) When you see an opening bracket, do your recursive call to expression. 不要这样做,然后:)当你看到一个左括号时,你做递归调用表达式。 At the end of the expresssion, either you find another operator (and so you're not at the end of the expression after all), or a right-bracket, in which case you return from the evaluate. 在表达结束时,要么你找到另一个运算符(所以你毕竟不是在表达式的末尾),或者右括号,在这种情况下你从评价中返回。

Either you use a parser generator such as JavaCUP or ANTLR . 要么使用解析器生成器,如JavaCUPANTLR Write up a BNF of your expression and generate a parser. 写下你的表达式的BNF并生成一个解析器。 Here is a sample grammar that would get you started: 这是一个可以帮助您入门的示例语法:

Expression ::= Digit
            |  LeftBracket Expression Plus Expression RightBracket
            |  LeftBracket Expression Minus Expression RightBracket
            |  LeftBracket Expression RightBracket

A "hacky" way of doing it yourself would be to look for the first ) backtrack to the closest ( look at the parenthesis free expression in between, simply split on the operator symbols and evaluate. 这样做的“哈克”的方式自己会去寻找第一)回溯到最近的(看括号自由的表达,简单地之间的分裂上操作符号和评估。

Use a StringTokenizer to split your input string into parenthesis, operators and numbers, then iterate over your tokens, making a recursive call for every open-parens, and exiting your method for every close parenthesis. 使用StringTokenizer将输入字符串拆分为括号,运算符和数字,然后迭代您的标记,对每个开放的parens进行递归调用,并为每个紧密括号退出方法。

I know you didn't ask for code, but this works for valid input: 我知道你没有要求代码,但这适用于有效的输入:

public static int eval(String expr) {
    StringTokenizer st = new StringTokenizer(expr, "()+- ", true);
    return eval(st);
}

private static int eval(StringTokenizer st) {
    int result = 0;
    String tok;
    boolean addition = true;
    while ((tok = getNextToken(st)) != null) {
        if (")".equals(tok))
            return result;
        else if ("(".equals(tok))
            result = eval(st);
        else if ("+".equals(tok))
            addition = true;
        else if ("-".equals(tok))
            addition = false;
        else if (addition)
            result += Integer.parseInt(tok);
        else
            result -= Integer.parseInt(tok);
    }
    return result;
}

private static String getNextToken(StringTokenizer st) {
    while (st.hasMoreTokens()) {
        String tok = st.nextToken().trim();
        if (tok.length() > 0)
            return tok;
    }
    return null;
}

It would need better handling of invalid input, but you get the idea... 它需要更好地处理无效输入,但你明白了......

I would recommend changing the infix input into postfix and then evaluating it, rather than reducing the expression infix-wise. 我建议将中缀输入更改为后缀,然后对其进行评估,而不是减少表达式中缀。 There are already well defined algorithms for this and it doesn't come with the inherent multiple-nested-parentheses parsing problems. 已经有很好的定义算法,并没有固有的多嵌套括号解析问题。

Take a look at the Shunting Yard Algorithm to convert to postfix/RPN then evaluate it using a stack using Postfix Operations . 看看Shunting Yard算法转换为postfix / RPN,然后使用Postfix Operations使用堆栈对其进行评估。 This is fast (O(n)) and reliable. 这很快(O(n))且可靠。

HTH HTH

I would suggest taking an approach that more closely resembles the one described in this old but (in my opinion) relevant series of articles on compiler design. 我建议采取更类似于中描述的一种方法这个旧的,但(在我看来)相关系列的编译器设计的文章。 I found that the approach of using small functions/methods that parse parts of the expression to be highly effective. 我发现使用解析部分表达式的小函数/方法非常有效。

This approach allows you to decompose your parsing method into many sub-methods whose names and order of execution closely follows the EBNF you might use to describe the expressions to be parsed. 此方法允许您将解析方法分解为许多子方法,这些子方法的名称和执行顺序紧跟在您可能用于描述要解析的表达式的EBNF之后

也许为表达式运算符创建正则表达式 ,然后使用匹配来识别和分解您的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM