简体   繁体   English

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

[英]Efficient way to parse multiple digit arithmetic expression

For example, suppose I have a string expression "10.2*(8-6)/3+112.5" 例如,假设我有一个字符串表达式“ 10.2 *(8-6)/3+112.5”

I need to insert the number to a List and operator to a different List 我需要将数字插入到列表中,并将运算符插入到其他列表中

My current (ugly) approach: 我目前的(丑陋的)方法:

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() + " ");
    }   
}

Test run: 测试运行:

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

It somewhat works, but I'm sure there are cleaner, more efficient approach. 它多少有些用,但我敢肯定有更清洁,更有效的方法。 Thanks in advance! 提前致谢!

I would create a list containing all operations to check it later: 我将创建一个包含所有操作的列表,以便以后进行检查:

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

and optimize the way you check decimal numbers: 并优化检查十进制数字的方式:

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

Then, when you get the Character from the String, simply check: 然后,当您从字符串中获取字符时,只需检查:

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--;
    }
}

Check a working demo here 在这里查看工作演示

You could also use basic regular expression matching to separate operands from operators in the expression you want to parse. 您还可以使用基本的正则表达式匹配将要解析的表达式中的操作数与运算符分开。

Here's a working example of that using the regular expression [^\\*\\-\\(\\)\\/\\+]+ . 这是一个使用正则表达式[^\\*\\-\\(\\)\\/\\+]+的工作示例。 You'll find a detailed explanation of the regular expression used after the code and the idea behind the code as inline comments. 您将在代码后找到对正则表达式的详细说明,并以内联注释的形式了解代码背后的思想。

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

Explanation of the regular expression: The brackets just group a set of characters, in this case all the operators. 正则表达式的解释:方括号仅将一组字符(在此情况下为所有运算符)分组。 The ´^´ means that the group should contain all characters BUT the ones mentioned afterwards, so this group actually means "all non-operator characters". “ ^”表示该组应包含所有字符,但后面要提到的所有字符,因此该组实际上是指“所有非运营商字符”。 The operators mentioned afterwards are escaped by a \\ because otherwise they would be interpreted as special characters inside the regular expression. 后面提到的运算符用\\进行转义,因为否则它们将被解释为正则表达式内的特殊字符。 Finally with the non-escaped ´+´ after the bracket we indicate that we want to match sequences of one or more of the characters inside the bracket. 最后,在方括号后加上非转义的“ +”,表示要匹配方括号内一个或多个字符的序列。 Because we give the regular expression as a java string we actually need to escape twice, because \\ has to be escaped inside java strings. 因为我们将正则表达式作为Java字符串给出,所以实际上我们需要转义两次,因为\\必须在Java字符串中转义。

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

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