Java表达式解析器计算器调车场算法

编程入门 行业动态 更新时间:2024-10-13 18:26:12
本文介绍了Java表达式解析器计算器调车场算法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

因此,任务是为表达式计算器创建自己的解析器.例如:

So the task is to create our own parser for a expression calculator. For Example:

输入:3 + 2 * 1-6/3 输出:3

Input: 3+2*1-6/3 Output: 3

输入:3 ++ 2 输出:无效的表达式

Input: 3++2 Output: Invalid Expression

输入:-5 + 2 输出:-3

Input: -5+2 Output: -3

输入:5--2 输出:7

Input: 5--2 Output: 7

这里的代码解决了部分问题,除了它具有固定的输入并且不能解决负值之外,而且我还不确定它是否真的以运算符优先级解决了表达式. 但我已经对其进行了修改,以从用户那里获得输入表达式. 我一直想知道如何实施负值解决方案.帮助任何人?

The code here solves a part of the problem except that it has a fixed input and negative values cannot be solved, And I'm not quite sure yet if it really does solve the expression with operator precedence. but I already modified it to get an input expression from the user. and I've been wondering for hours how to implement the solving for negative values. help anyone?

请不要使用JAVASCRIPT引擎.

NO JAVASCRIPT ENGINE PLEASE.

这是当前代码

import java.util.*; public class ExpressionParser { // Associativity constants for operators private static final int LEFT_ASSOC = 0; private static final int RIGHT_ASSOC = 1; // Operators private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>(); static { // Map<"token", []{precendence, associativity}> OPERATORS.put("+", new int[] { 0, LEFT_ASSOC }); OPERATORS.put("-", new int[] { 0, LEFT_ASSOC }); OPERATORS.put("*", new int[] { 5, LEFT_ASSOC }); OPERATORS.put("/", new int[] { 5, LEFT_ASSOC }); } // Test if token is an operator private static boolean isOperator(String token) { return OPERATORS.containsKey(token); } // Test associativity of operator token private static boolean isAssociative(String token, int type) { if (!isOperator(token)) { throw new IllegalArgumentException("Invalid token: " + token); } if (OPERATORS.get(token)[1] == type) { return true; } return false; } // Compare precedence of operators. private static final int cmpPrecedence(String token1, String token2) { if (!isOperator(token1) || !isOperator(token2)) { throw new IllegalArgumentException("Invalid tokens: " + token1 + " " + token2); } return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0]; } // Convert infix expression format into reverse Polish notation public static String[] expToRPN(String[] inputTokens) { ArrayList<String> out = new ArrayList<String>(); Stack<String> stack = new Stack<String>(); // For each token for (String token : inputTokens) { // If token is an operator if (isOperator(token)) { // While stack not empty AND stack top element // is an operator while (!stack.empty() && isOperator(stack.peek())) { if ((isAssociative(token, LEFT_ASSOC) && cmpPrecedence(token, stack.peek()) <= 0) || (isAssociative(token, RIGHT_ASSOC) && cmpPrecedence(token, stack.peek()) < 0)) { out.add(stack.pop()); continue; } break; } // Push the new operator on the stack stack.push(token); } // If token is a left bracket '(' else if (token.equals("(")) { stack.push(token); // } // If token is a right bracket ')' else if (token.equals(")")) { while (!stack.empty() && !stack.peek().equals("(")) { out.add(stack.pop()); } stack.pop(); } // If token is a number else { // if(!isOperator(stack.peek())){ // out.add(String.valueOf(token*10)); // } out.add(token); } } while (!stack.empty()) { out.add(stack.pop()); } String[] output = new String[out.size()]; return out.toArray(output); } public static double RPNtoDouble(String[] tokens) { Stack<String> stack = new Stack<String>(); // For each token for (String token : tokens) //for each { // If the token is a value push it onto the stack if (!isOperator(token)) { stack.push(token); } else { // Token is an operator: pop top two entries Double d2 = Double.valueOf( stack.pop() ); Double d1 = Double.valueOf( stack.pop() ); //Get the result Double result = tokenpareTo("*") == 0 ? d1 * d2 : tokenpareTo("/") == 0 ? d1 / d2 : tokenpareTo("+") == 0 ? d1 + d2 : d1 - d2; // Push result onto stack stack.push( String.valueOf( result )); } } return Double.valueOf(stack.pop()); } public static void main(String[] args) throws Exception{ Scanner in = new Scanner(System.in); String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))"; while(true){ try{ System.out.println("Enter Your Expression"); //String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" "); String[] input = in.nextLine() .split(reg); String[] output = expToRPN(input); // Build output RPN string minus the commas System.out.print("Stack: "); for (String token : output) { System.out.print("[ ");System.out.print(token + " "); System.out.print("]"); } System.out.println(" "); // Feed the RPN string to RPNtoDouble to give result Double result = RPNtoDouble( output ); System.out.println("Answer= " + result); }catch (NumberFormatException | EmptyStackException nfe){ System.out.println("INVALID EXPRESSION"); } } } }

更新的代码: 新增:unaryToexp()函数. 我想做的是,每当出现一个-"时,代码会将它作为另一个运算符将其更改为"_",以将其视为二进制文件,并且此运算符将乘以-1进行乘法运算(我首先要添加[- 1]和[*]到rpn堆栈).仍然有问题.

UPDATED CODE: Added: unaryToexp() function. what I wanted to do was that everytime a " - " occurs, the code treats it as a binary by changing it to " _ " as another operator and this operator solves multiplies thing by -1 (what I wanted first was to add [-1] and [*] to the rpn stack). still got problems here.

编译器说:

Enter Your Expression -5+3 Stack: [ ][ 5 ][ - ][ 3 ][ + ] Exception in thread "main" java.lang.NumberFormatException: empty String at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:10 11) at java.lang.Double.valueOf(Double.java:504) at ExpressionParser.RPNtoDouble(ExpressionParser.java:160) at ExpressionParser.main(ExpressionParser.java:194)*

我认为它与Double d1 = Double.valueOf( stack.pop() );有关,因为它仍然弹出另外两个值,在这里我只需要一个值即可解决一元运算符.有帮助吗?

I think it has something to do with the Double d1 = Double.valueOf( stack.pop() ); cause it still pops another two values, where I only need one for a solving a unary operator. any help?

public class ExpressionParser { // Associativity constants for operators private static final int LEFT_ASSOC = 0; private static final int RIGHT_ASSOC = 1; // Operators private static final Map<String, int[]> OPERATORS = new HashMap<String, int[]>(); static { // Map<"token", []{precendence, associativity}> OPERATORS.put("-", new int[] { 0, LEFT_ASSOC }); OPERATORS.put("+", new int[] { 0, LEFT_ASSOC }); OPERATORS.put("*", new int[] { 5, LEFT_ASSOC }); OPERATORS.put("/", new int[] { 5, LEFT_ASSOC }); OPERATORS.put("_", new int[] { 5, RIGHT_ASSOC }); } // Test if token is an operator private static boolean isOperator(String token) { return OPERATORS.containsKey(token); } // Test associativity of operator token private static boolean isAssociative(String token, int type) { if (!isOperator(token)) { throw new IllegalArgumentException("Invalid token: " + token); } if (OPERATORS.get(token)[1] == type) { return true; } return false; } // Compare precedence of operators. private static final int cmpPrecedence(String token1, String token2) { if (!isOperator(token1) || !isOperator(token2)) { throw new IllegalArgumentException("Invalid tokens: " + token1 + " " + token2); } return OPERATORS.get(token1)[0] - OPERATORS.get(token2)[0]; } // CONVERT UNARY OPERATORS public static String[] unaryToexp(String[] inputTokens) { ArrayList<String> out = new ArrayList<String>(); Stack<String> stack = new Stack<String>(); //if token is an unary minus for (String token : inputTokens) { if( ((token == "-") && (isOperator(stack.peek()) || stack.empty() ))){ // token = "_"; } else if (token == "-"){ token = "-"; } out.add(token); while (!stack.empty()) { out.add(stack.pop()); } } String[] output = new String[out.size()]; return out.toArray(output); } // Convert infix expression format into reverse Polish notation public static String[] expToRPN(String[] inputTokens) { ArrayList<String> out = new ArrayList<String>(); Stack<String> stack = new Stack<String>(); // For each token for (String token : inputTokens) { // If token is an operator if (isOperator(token)) { // While stack not empty AND stack top element // is an operator while (!stack.empty() && isOperator(stack.peek())) { if ((isAssociative(token, LEFT_ASSOC) && cmpPrecedence(token, stack.peek()) <= 0) || (isAssociative(token, RIGHT_ASSOC) && cmpPrecedence(token, stack.peek()) < 0)) { out.add(stack.pop()); continue; } break; } // Push the new operator on the stack stack.push(token); } // If token is a left bracket '(' else if (token.equals("(")) { stack.push(token); // } // If token is a right bracket ')' else if (token.equals(")")) { while (!stack.empty() && !stack.peek().equals("(")) { out.add(stack.pop()); } stack.pop(); } // If token is a number else { out.add(token); } } while (!stack.empty()) { out.add(stack.pop()); } String[] output = new String[out.size()]; return out.toArray(output); } public static double RPNtoDouble(String[] tokens) { Stack<String> stack = new Stack<String>(); // For each token for (String token : tokens) { // If the token is a value push it onto the stack if (!isOperator(token)) { stack.push(token); } else { // Token is an operator: pop top two entries Double d2 = Double.valueOf( stack.pop() ); Double d1 = Double.valueOf( stack.pop() ); //Get the result Double result = tokenpareTo("_") == 0 ? d2 * -1 : tokenpareTo("*") == 0 ? d1 * d2 : tokenpareTo("/") == 0 ? d1 / d2 : tokenpareTo("+") == 0 ? d1 + d2 : d1 - d2; // Push result onto stack stack.push( String.valueOf( result )); } } return Double.valueOf(stack.pop()); } public static void main(String[] args) throws Exception{ Scanner in = new Scanner(System.in); String reg = "((?<=[<=|>=|==|\\+|\\*|\\-|\\_|<|>|/|=])|(?=[<=|>=|==|\\+|\\*|\\-|<|>|/|=]))"; while(true){ //try{ System.out.println("Enter Your Expression"); //String[] input = "( 1 + 2 ) * ( 3 / 4 ) - ( 5 + 6 )".split(" "); String[] input = in.nextLine() .split(reg); String[] unary = unaryToexp(input); //.split(reg); String[] output = expToRPN(unary); // Build output RPN string minus the commas System.out.print("Stack: "); for (String token : output) { System.out.print("[ ");System.out.print(token); System.out.print(" ]"); } System.out.println(" "); // Feed the RPN string to RPNtoDouble to give result Double result = RPNtoDouble( output ); System.out.println("Answer= " + result); //}catch (){ //System.out.println("INVALID EXPRESSION"); } } } }

推荐答案

看看一些示例,并尝试找到一条规则,以区分负值和运算符. 像这样的规则:

Take a look at some examples and try to find a rule how to distinguish negative values from operators. A rule like:

if (token is + or -) and next token is a number and (the previous token was empty or the prvious token was ')' or another operator) then it is a sign to the current value.

您可以遍历原始令牌列表并根据此规则创建新的令牌列表. 我刚刚编写了这样的表达式求值器,并且有一个迭代器用于将表达式标记化.计划在GitHub上进行一些扩展后将其发布.

You could iterate through your original token list and create a new token list based on this rules. I have just written such an expression evaluator and have an iterator for tokenizing expressions at hand. plan to publish it after some extensions on GitHub.

这是迭代器,引用和调用应该很清楚,由于支持变量/函数和多字符运算符,因此它有点复杂:

Here is the iterator, the references and calls should be clear, it is a bit more complex because of support for variables/functions and multi-character operators:

private class Tokenizer implements Iterator<String> { private int pos = 0; private String input; private String previousToken; public Tokenizer(String input) { this.input = input; } @Override public boolean hasNext() { return (pos < input.length()); } private char peekNextChar() { if (pos < (input.length() - 1)) { return input.charAt(pos + 1); } else { return 0; } } @Override public String next() { StringBuilder token = new StringBuilder(); if (pos >= input.length()) { return previousToken = null; } char ch = input.charAt(pos); while (Character.isWhitespace(ch) && pos < input.length()) { ch = input.charAt(++pos); } if (Character.isDigit(ch)) { while ((Character.isDigit(ch) || ch == decimalSeparator) && (pos < input.length())) { token.append(input.charAt(pos++)); ch = pos == input.length() ? 0 : input.charAt(pos); } } else if (ch == minusSign && Character.isDigit(peekNextChar()) && ("(".equals(previousToken) || ",".equals(previousToken) || previousToken == null || operators .containsKey(previousToken))) { token.append(minusSign); pos++; token.append(next()); } else if (Character.isLetter(ch)) { while (Character.isLetter(ch) && (pos < input.length())) { token.append(input.charAt(pos++)); ch = pos == input.length() ? 0 : input.charAt(pos); } } else if (ch == '(' || ch == ')' || ch == ',') { token.append(ch); pos++; } else { while (!Character.isLetter(ch) && !Character.isDigit(ch) && !Character.isWhitespace(ch) && ch != '(' && ch != ')' && ch != ',' && (pos < input.length())) { token.append(input.charAt(pos)); pos++; ch = pos == input.length() ? 0 : input.charAt(pos); if (ch == minusSign) { break; } } if (!operators.containsKey(token.toString())) { throw new ExpressionException("Unknown operator '" + token + "' at position " + (pos - token.length() + 1)); } } return previousToken = token.toString(); } @Override public void remove() { throw new ExpressionException("remove() not supported"); } }

更多推荐

Java表达式解析器计算器调车场算法

本文发布于:2023-11-29 12:13:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1646366.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:调车场   表达式   计算器   算法   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!