所以任务是为表达式计算器创建自己的解析器。例如:
输入:3 + 2 * 1-6 / 3 输出:3
输入:3 ++ 2 输出:表达式无效
输入:-5 + 2 输出:-3
输入:5--2 输出:7
这里的代码解决了问题的一部分,除了它有一个固定的输入而负值无法解决,而且我还不确定它是否确实解决了运算符优先级的表达式。 但我已经修改它以获取用户的输入表达式。 而且我一直想知道如何实现负值的求解。帮助任何人?
没有JAVASCRIPT引擎请。
这是当前的代码
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 = token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 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堆栈)。这里仍有问题。
编译说:
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() );
有关,因为它仍会弹出另外两个值,我只需要一个来解决一元运算符。有什么帮助吗?
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 = token.compareTo("_") == 0 ? d2 * -1 :
token.compareTo("*") == 0 ? d1 * d2 :
token.compareTo("/") == 0 ? d1 / d2 :
token.compareTo("+") == 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"); }
}
}
}
答案 0 :(得分:1)
你在这里:
private static final ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
public static String eval(String matlab_expression){
if(matlab_expression == null){
return "NULL";
}
String js_parsable_expression = matlab_expression
.replaceAll("\\((\\-?\\d+)\\)\\^(\\-?\\d+)", "(Math.pow($1,$2))")
.replaceAll("(\\d+)\\^(\\-?\\d+)", "Math.pow($1,$2)");
try{
return engine.eval(js_parsable_expression).toString();
}catch(javax.script.ScriptException e1){
return null; // Invalid Expression
}
}
答案 1 :(得分:1)
看一些示例,并尝试找到如何区分负值和运算符的规则。 像:
这样的规则 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上进行一些扩展后发布它。
编辑:这是迭代器,引用和调用应该是清楚的,由于支持变量/函数和多字符运算符,它有点复杂: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");
}
}
答案 2 :(得分:1)
你能不能使用javascript脚本引擎? (你需要对5--2
表达式进行一些调整)下面的代码输出:
3+2*1-6/3 = 3.0
3++2 = Invalid Expression
-5+2 = -3.0
5--2 = 7.0
代码:
public class Test1 {
static ScriptEngine engine;
public static void main(String[] args) throws Exception {
engine = new ScriptEngineManager().getEngineByName("JavaScript");
printValue("3+2*1-6/3");
printValue("3++2");
printValue("-5+2");
printValue("5--2");
}
private static void printValue(String expression) {
String adjustedExpression = expression.replaceAll("--", "- -");
try {
System.out.println(expression + " = " + engine.eval(adjustedExpression));
} catch (ScriptException e) {
System.out.println(expression + " = Invalid Expression");
}
}
}
答案 3 :(得分:1)
您可以使用专门为此类任务设计的解析器生成器(如JavaCC或antlr),而不是重新发明轮子。 This is a nice example一个简单的表达式解析器和评估器,在几十行JavaCC中。