解析多位数算术表达式的有效方法

时间:2015-08-17 15:19:40

标签: java parsing

例如,假设我有一个字符串表达式" 10.2 *(8-6)/3 +112.5"

我需要将数字插入List和运算符到不同的List

我当前(丑陋)的做法:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;


public class Test {



    public static void main (String args[]) 
    {
        String expression = "10.2*(8-6)/3+112.5"; 
        List<Character> firstList = new ArrayList<Character>();
        List<String> secondList = new ArrayList<String>();

         // Temporary string to hold the number
        StringBuilder temp = new StringBuilder();

        for(int i = 0; i != expression.length(); ++i)
        {           
            if(Character.isDigit(expression.charAt(i)))
            {
                /* If we encounter a digit, read all digit next to it and append to temp
                 * until we encounter an operator.
                 */
                temp.append(expression.charAt(i));

                while((i+1) != expression.length() && (Character.isDigit(expression.charAt(i+1)) 
                                                  || expression.charAt(i+1) == '.'))
                {
                    temp.append(expression.charAt(++i));
                }

                // Next token is either an operator or end of expression
                // Put the number into the list and clear temp for next number
                secondList.add(temp.toString());
                temp.delete(0, temp.length());
            }
            // Getting here means the token is an operator
            else
                firstList.add(expression.charAt(i));
        }

        System.out.print("Numbers: ");
        for(String str : secondList)
            System.out.print(str + " ");

        System.out.println();
        System.out.print("Operators: ");
        for(Character ch  : firstList)
            System.out.print(ch.toString() + " ");
    }   
}

试运行:

Numbers: 10.2 8 6 3 112.5 
Operators: * ( - ) / + 

它有点奏效,但我确信有更清洁,更有效的方法。提前谢谢!

2 个答案:

答案 0 :(得分:0)

我会创建一个包含所有操作的列表,以便稍后检查它:

List<Character> operations = new ArrayList<Character>();
operations.add('*'); // put all operations * / ( ) etc...

并优化检查十进制数字的方式:

while (!operations.contains(expression.charAt(i)) && i < (expression.length()-1)) 
                    i++;     
secondList.add(expression.substring(c, i));

然后,当您从字符串中获取字符时,只需检查:

for(int i = 0; i != expression.length(); ++i) {
    if (operations.contains(expression.charAt(i))) {
        firstList.add(expression.charAt(i));
    } else {
        int c = i;
        while (!operations.contains(expression.charAt(i)) && i < (expression.length()-1)) 
                i++; 

        secondList.add(expression.substring(c, i));
        if (i < (expression.length()-1)) i--;
    }
}

检查working demo here

答案 1 :(得分:0)

您还可以使用基本正则表达式匹配来将操作数与要解析的表达式中的运算符分开。

以下是使用正则表达式[^\*\-\(\)\/\+]+的示例。您将在代码后面找到正则表达式的详细说明,并将代码背后的想法作为内联注释。

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ArithmeticExpressionParser 
{
    public void parse(String expression, List<Character> operatorList, 
            List<String> operandList)
    {
        // Create a string of (escaped) operators. Just append all other 
        // operators that you may need.
        StringBuffer operators = new StringBuffer();
        operators.append("\\*");  // *
        operators.append("\\-");  // -
        operators.append("\\(");  // (
        operators.append("\\)");  // )
        operators.append("\\/");  // /
        operators.append("\\+");  // +

        // Compile and match a regular expression matching sequences of
        // non-operator characters against the given expression.
        Pattern pattern = Pattern.compile("[^" + operators + "]+");
        Matcher matcher = pattern.matcher(expression);

        // For each matched subsequence (which represents an operand)...
        int previousEnd = 0;
        while(matcher.find()) {

            // ... add all the operator characters between the end of the last
            // match and the beginning of this match to the operator list ...
            for (int i=previousEnd; i<matcher.start(); i++) {
                operatorList.add(expression.charAt(i));
            }

            // ... and the current match to the operand list.
            operandList.add(
                    expression.substring(matcher.start(), matcher.end()));

            previousEnd = matcher.end();
        }
    }
}

正则表达式的说明: 括号只是对一组字符进行分组,在本例中为所有运算符。 '^'表示该组应包含所有字符但后面提到的字符,因此该组实际上意味着“所有非操作符”。 之后提到的运算符由\转义,否则它们将被解释为正则表达式中的特殊字符。最后,在括号后面的非转义'+'表示我们想要匹配括号内的一个或多个字符的序列。因为我们将正则表达式作为java字符串提供,所以我们实际上需要转义两次,因为\必须在java字符串中进行转义。

相关问题