0

I am trying to build a calculator by converting infix to postfix but I've been having trouble with handling cos, sin, and tan. My current approach is to use regular expressions to split the input string by the cos, sin, etc and numbers then placing them into indexes of an ArrayList. I have been able to get cos0 to split into two ArrayList indexes, but the index that's supposed to hold cos turns up empty. I don't know if I am using regular expressions wrong or if it's something else.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Matcher;



public class Calculator {

    //String sin = "sin";
    //String cos = "cos";
    //String tan = "tan";

    public static void main(String[] args) {
        new Calculator().run();
    }

    public void run() {
        Calculator Eval = new Calculator();
        Scanner keyboard = new Scanner(System.in);
        System.out.println("Please give an equation.");

        String input = keyboard.next();

        System.out.print(Eval.infixToPostfix(input));
    }

    public double infixToPostfix(String input)
    {

        Stack<String>infixStack = new Stack<>();
        ArrayList<String> exp = new ArrayList<>(Arrays.asList(input.split("(cos|tan|sin\\d\\D)")));

        String infix = "";

        for (int i = 0; i < exp.size(); i++)
        {
            if(exp.get(i).equals("")){
                continue;
            }
            if (exp.get(i).matches("([\\d])")) {

                infix = infix + exp.get(i);

            }else if(exp.get(i).matches("([\\D])"))
            {
                while(!infixStack.empty() && !infixStack.peek().matches("[\\(\\[\\{\\^]") && OperatorPriority(infixStack.peek(), exp.get(i) ))
                {
                    infix = infix + infixStack.peek();
                    infixStack.pop();
                }
                infixStack.push(exp.get(i));
            }else if(exp.get(i).matches("[(]"))
            {
                infixStack.push(exp.get(i));
            }else if(exp.get(i).matches("[)]"))
            {
                while(!infixStack.empty() && !infixStack.peek().matches("[(]"));
            {
                infix = infix + infixStack.peek();
                infixStack.pop();
            }
            infixStack.pop();
            }else if(exp.get(i).matches("[\\^]"))
            {
                infixStack.push(exp.get(i));
            }else if(exp.get(i).matches("[\\[]"))
            {
                infixStack.push(exp.get(i));
            }else if(exp.get(i).matches("[\\]]"))
            {
                while(!infixStack.empty() && !infixStack.peek().matches("[\\(\\[]"))
                {
                    infix = infix + infixStack.peek();
                    infixStack.pop();
                }

                infixStack.pop();
            } else if(exp.get(i).matches("[\\{]"))
            {
                infixStack.push(exp.get(i));
            }else if(exp.get(i).matches("[\\}]"))
            {
                while(!infixStack.empty() && !infixStack.peek().matches("[\\(\\{\\[]"))
                {
                    infix = infix + infixStack.peek();
                    infixStack.pop();
                }
                infixStack.pop();
            }
        }

        while(!infixStack.empty())
        {
            infix = infix + infixStack.peek();
            infixStack.pop();
        }
        return evaluatePostFix(infix);
    }

    public double evaluatePostFix(String infix) {
        Stack<Double> equation = new Stack<Double>();
        ArrayList<String> postfixArray = new ArrayList<>(Arrays.asList(infix.split("(?<=[\\w'(cos|tan|sin)'\\d])|(?=[\\w'(cos|tan|sin)'\\d])")));


        double first;
        double second;

        try {
            for (int i = 0; i < postfixArray.size(); i++) {
                if (postfixArray.get(i).matches("([\\d])")) {
                    double d = Double.parseDouble(postfixArray.get(i));
                    equation.push(d - '0');
                }else if(postfixArray.get(i).matches("([sin])"))
                {
                    first = equation.pop();
                    //second = equation.pop();
                    double result = Math.sin(Math.toRadians(first));
                    equation.push(result);
                }else if(postfixArray.get(i).matches("([cos])"))
                {
                    first = equation.pop();
                    //second = equation.pop();
                    double result = Math.cos(Math.toRadians(first));
                    equation.push(result);
                }else if(postfixArray.get(i).matches("([tan])"))
                {
                    first = equation.pop();
                    //second = equation.pop();
                    double result = Math.tan(Math.toRadians(first));
                    equation.push(result);
                }

                if (postfixArray.get(i).matches("[*]")) {
                    first = equation.pop();
                    second = equation.pop();
                    double result = first * second;
                    equation.push(result);
                }

                if (postfixArray.get(i).matches("[/]")) {
                    first = equation.pop();
                    second = equation.pop();
                    double result = second / first;
                    equation.push(result);
                }

                if (postfixArray.get(i).matches("[+]")) {
                    first = equation.pop();
                    second = equation.pop();
                    double result = first + second;
                    equation.push(result);
                }

                if (postfixArray.get(i).matches("[-]")) {
                    first = equation.pop();
                    second = equation.pop();
                    double result = first - second;
                    equation.push(result);
                }

                if (postfixArray.get(i).matches("[(^)]")) {
                    first = equation.pop();
                    second = equation.pop();
                    double result = Math.pow(first, second);
                    equation.push(result);
                }
            }

            if (!equation.isEmpty()) {
                return equation.pop();
            } else
                return 0.0;
        } catch (Exception e ) {
            return 0.0;
        }
    }

    int OperatorWeight(String op)
    {
        int weight = 1;
        if(op.equals("+") || op.equals("-"))
        {
            weight = 1;
        }else if(op.equals("*") || op.equals("/") )
        {
            weight = 2;
        }else if(op.equals("^"))
        {
            weight = 3;
        }
        return weight;
    }

    boolean OperatorPriority(String operator1, String operator2)
    {
        int weight1 = OperatorWeight(operator1);
        int weight2 = OperatorWeight(operator2);

        if(weight1 == weight2)
        {
            return true;
        }
        return weight1 > weight2;
    }
}
1
  • Edit your question's title into something general and yet relevant: "How to split String using regex and insert into ArrayList?" Commented Nov 10, 2016 at 19:50

2 Answers 2

1

Assuming the following input format:

valid - cos49

invalid - cos43.54

invalid - sin(angle)

You can divide your string into two groups:

  1. sin|cos|tan
  2. digits

So your regex should look like this:

Pattern p = Pattern.compile("(sin|cos|tan)|(\\d+)");
Matcher m = p.matcher("cos60");
ArrayList<String> a = new ArrayList<>();
while (m.find())
    a.add(m.group(0));

System.out.println(a.toString());

Read how the matcher class works. Hope it helps

Sign up to request clarification or add additional context in comments.

1 Comment

Yes that helps a lot! Thank you!
1

I am not quite sure what your problem is, but this is how I understood it: You have a string "cos90" and want to get the "cos" as operator and "90" as value, but you are not getting the "cos".

First thing your regex is a bit wrong.

(cos|tan|sin\\d\\D)

This means "cos" or "tan" or "sin\d\D", but you want

(cos|tan|sin)\\d\\D

Which is "cos", "tan" or "sin" followed by "\d\D". I suggest to look for a regex tester online to see what your expressions result in.

Next you will not be able to retrieve the "cos" because you are splitting on it. This means it wont be included in your exp list. What you need is a Matcher to iterate through your string and collect all matches. Then you will have both your operator and value available

4 Comments

Yeah you understood correctly. For cos90 I would want cos in index 0 and 90 in index 1. I changed my regex splitter to that format and it placed everything into the 0 index of my ArrayList. Is that what you were talking about?
I would use a ´Matcher´ to iterate the string with everything you want. docs.oracle.com/javase/7/docs/api/java/util/regex/Matcher.html Create a regex that would split your input into the different operation-value pairs and then use ´Find()´ to go through them one-by-one.
Is this kind of what you're talking about? @Mats391 It's not finding a pattern though. I can't tell what's causing that problem. gist.github.com/anonymous/0a1d432b9e14505d269567aaa3401941
Yes that definitely helped but thank you for your help! @Mats391

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.