×

Welcome to TagMyCode

Please login or create account to add a snippet.
0
0
 
0
Language: Java
Posted by: Shamir Yona
Added: Nov 23, 2015 4:22 AM
Views: 1919
Tags: no tags
  1. /*
  2.  * File name: EqSolver.java
  3.  * Evaulate an Arithmetic expression - supports Add., Sub. Mult., Div. and
  4.  * negative numbers.
  5.  */
  6. package OtherTests;
  7.  
  8. import java.util.Stack;
  9.  
  10. /**
  11.  *
  12.  * @author shayzukerman
  13.  */
  14. public class EqSolver
  15. {  
  16.     /**
  17.      * Types of expected tokens in input expression:
  18.      */
  19.     public enum TOKEN
  20.     {
  21.         ERROR,
  22.         NONE,
  23.         NUMBER,
  24.         MINUS,
  25.         OPERATOR,
  26.         SPACE
  27.     };
  28.    
  29.     private static final String NUM_OPERATORS = "+-*/"; // used to verify operations.
  30.    
  31.     /**
  32.      * Evaluate the Arithmetic expression:
  33.      * @param mathEpr input expression
  34.      * @return its value.
  35.      */
  36.     @SuppressWarnings("empty-statement")
  37.     static int solveMathExp(String mathEpr)
  38.     {
  39.         int solution = 0;
  40.         String errorStr = null;
  41.         // Convert the input string to char array to solve some time:
  42.         int inpLen = mathEpr.length();
  43.        
  44.         int nextPos = 0;      // Next position in the input string:
  45.         int pos;              // current index in string.
  46.         char ch;
  47.         TOKEN currToken;       // Type of the next xpected token in input
  48.         int currNum;          // Last identified number;
  49.         char currOper = '\0'; // last identfied  operator
  50.         boolean firstDigitFound; // Used for hadling minus signs:
  51.        
  52.         // Stack holding the numbers to be summed:
  53.         Stack<Integer> numStk = new Stack<>();
  54.  
  55.         // Precedence - Should the number put in stack or immedialty used
  56.         // for evaluation of sub expression:
  57.         boolean evalSubExp = false;
  58.         int numSign;
  59.        
  60.         boolean cont = true; // Loop flag
  61.        
  62.         // First expected token:
  63.         firstDigitFound = false;
  64.         numSign = 1;
  65.         currNum = 0;
  66.        
  67.         currToken = TOKEN.NUMBER;
  68.         // Scan the input line:
  69.         pos = 0;
  70.         while (cont)
  71.         {
  72.             if (pos == inpLen)
  73.             {
  74.                 ch = ' ';
  75.                 cont = false;
  76.             }
  77.             else
  78.             {
  79.                 // Skip over spaces:
  80.                 for (; pos < inpLen && Character.isWhitespace(mathEpr.charAt(pos)); pos++);
  81.                 ch = mathEpr.charAt(pos++);
  82.             }
  83.             TOKEN chToken = char2Token(ch);
  84.             if (chToken == TOKEN.ERROR)
  85.             {
  86.                 errorStr = String.format("Unexpected character \"%c\" in offset: %d\n",
  87.                         ch, (1 + nextPos + pos));
  88.                 currToken = TOKEN.ERROR;
  89.                 break;
  90.             }
  91.             if (currToken == TOKEN.NUMBER)
  92.             {
  93.                 switch (chToken)
  94.                 {
  95.                     case NUMBER:
  96.                         if (!firstDigitFound)
  97.                             firstDigitFound = true;
  98.                         currNum = currNum * 10 + (ch - '0');
  99.                         break;
  100.  
  101.                     case MINUS:
  102.                         // IF the Minus sight preceeds any digit
  103.                         // then treat it as part of the number.
  104.                         // Otherwise - treat it as an operator:
  105.                         if (!firstDigitFound)
  106.                         {
  107.                             numSign *= -1;
  108.                             break;
  109.                         }
  110.                     // Operator, "-" or anything else:
  111.                     // Take care of the number:
  112.                     default:
  113.                         // First of all, make sure to return to the same
  114.                         // character in the next iteration:
  115.                         pos--;
  116.                        
  117.                         currNum *= numSign;
  118.  
  119.                         // Determine what to do:
  120.                         // Does Operation's precedence requires evaluation now or later:
  121.                         if (evalSubExp)
  122.                         {
  123.                             // Prev. operator is "=" - change number sign:
  124.                             if (currOper == '-')
  125.                                 currNum *= -1;
  126.                             else  // Mult,div - evaluate the expression
  127.                             {
  128.                                 if (numStk.size() == 0)
  129.                                 {
  130.                                     System.out.format("Invalid expression - missing number Pos: %d\n", nextPos);
  131.                                     cont = false;
  132.                                     break;
  133.                                 }
  134.                                 int popNum = numStk.pop();
  135.                                 currNum = evalOperation(currOper, popNum, currNum);
  136.                             }
  137.                         }
  138.                         // Store the number for the next operations:
  139.                         numStk.push(currNum);
  140.                         // Prepare for the next number:
  141.                         firstDigitFound = false;
  142.                         numSign = 1;
  143.                         currNum = 0;
  144.                         // The next token to find:
  145.                         currToken = TOKEN.OPERATOR;
  146.                         break;
  147.                 }
  148.             }
  149.             else if (currToken == TOKEN.OPERATOR)
  150.             {
  151.                 if (chToken == TOKEN.MINUS || chToken == TOKEN.OPERATOR)
  152.                 {
  153.                     currOper = ch;
  154.                     // Determine if the operation should be immediately evaluated:
  155.                     evalSubExp = (currOper != '+');
  156.                     currToken = TOKEN.NUMBER;
  157.                 }
  158.             }
  159.         }
  160.         // Is the expression wrong:
  161.         if (currToken != TOKEN.ERROR)
  162.         {
  163.             // Sum the contents of the stack:
  164.             if (numStk.size() > 0)
  165.             {
  166.                 solution = numStk.pop();
  167.                 while (numStk.size() > 0)
  168.                     solution += numStk.pop();
  169.             }
  170.         }
  171.         return(solution);
  172.     }
  173.    
  174.     /**
  175.      * Return the token the input character is belonging to:
  176.      * @param ch
  177.      * @return
  178.      */
  179.     static private TOKEN char2Token(char ch)
  180.     {
  181.         TOKEN retVal = TOKEN.ERROR;
  182.  
  183.         if (Character.isDigit(ch))
  184.             retVal = TOKEN.NUMBER;
  185.         else if (ch == '-')
  186.             retVal = TOKEN.MINUS;
  187.         else if (Character.isWhitespace(ch))
  188.             retVal = TOKEN.SPACE;
  189.         else if (NUM_OPERATORS.indexOf(ch) != -1)
  190.             retVal = TOKEN.OPERATOR;
  191.  
  192.         return(retVal);
  193.     }
  194.        
  195.     /**
  196.      * Evaluate the basic Arithmetic operation,
  197.      * @param operChar - Operator
  198.      * @param a
  199.      * @param b
  200.      * @return
  201.      * Note: There is no exceptions on Divide by zero ...
  202.      */
  203.     static private int evalOperation(char operChar, int a, int b)
  204.     {
  205.         switch (operChar)
  206.         {
  207.             case '+':
  208.                 return(a + b);
  209.             case '-':
  210.                 return(a - b);
  211.             case '*':
  212.                 return(a * b);
  213.             case '/': // No exceptions ....
  214.                 return((b != 0) ? a / b : 0);
  215.         }
  216.        
  217.         return(-1);
  218.     }
  219.    
  220.        
  221.     public static void main(String[] args)
  222.     {
  223.         //String inpExp = "-12 + 35 * 4 - -12";
  224.         String inpExp = "1 + 2 * 3 - -5 * 6 - 18 / 6 + 2";
  225.         int val = solveMathExp(inpExp);
  226.         System.out.println(inpExp + " = " + val);
  227.     }
  228. }
  229.