Infix to Postfix - java

I am trying to convert infix to postfix.For example :
"20 + 2 * 3 + (2*8 + 5)* 4" ->20 2 3 * + 2 8 * 5 + 4 * +
here is my code :
Stack<Character> s = new Stack<Character>();
String postfix = "";
boolean enter = true;
String infixExpr = "20 + 2 * 3 + (2*8 + 5)* 4";
for(int i = 0;i<infixExpr.length();i++){
if(Character.isDigit(infixExpr.charAt(i)) == true){
postfix = postfix + infixExpr.charAt(i);
}
if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
if(s.isEmpty() == true){
s.push(infixExpr.charAt(i));
}
else{
if(s.peek() == '*' || s.peek() == '/' || s.peek() == '+' || s.peek() == '-'){
while(s.isEmpty()== false){
postfix = postfix + s.pop();
}
s.push(infixExpr.charAt(i));
}
else{
s.push(infixExpr.charAt(i));
}
}
}
if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
if(s.isEmpty() == true){
s.push(infixExpr.charAt(i));
}
else{
if(s.peek()== '+' || s.peek() == '-' || s.peek() == '('){
s.push(infixExpr.charAt(i));
}
else if(s.peek() == '*' || s.peek() == '/'){
while(s.isEmpty()== false){
postfix = postfix + s.pop();
}
s.push(infixExpr.charAt(i));
}
}
if(infixExpr.charAt(i) == '('){
s.push(infixExpr.charAt(i));
}
if(infixExpr.charAt(i) == ')'){
while(enter){
if(s.peek() == '('){
enter = false;
}
else{
postfix = postfix + s.pop();
}
}
}
}
}
As it is written at the top I suppose to get "20 2 3 * + 2 8 * 5 + 4 * +" but I get "2023*+28*+54" which is wrong and I revised the code many times and still I cant see the problem. It would be great if anybody could help.

Spaces
You are not putting any spaces on your postfix variable. You are only checking if the current character is one of the "interesting" characters (digits, operators), but not whether it's a space. As a result, if the current character is a space, you just skip it and you don't copy it to the postfix.
Since the only things that you put in the postfix are characters that you have checked, you end up with no spaces at all.
You can solve it like this:
Add a boolean called inNumber, set it to true at first.
Whenever you process a digit, before you add it to postfix, check if inNumber is true. If so, add a space first.
If you have just processed a digit, set inNumber to true.
If you are processing an operator, set inNumber to false.
Whenever you add any operator to the stack, add a space first.
The idea about this inNumber is that digits that all belong to the same number should not have spaces between them. But if the digit is added to postfix after we have processed an operator in the previous round, then it belongs to a new number, so there should be a space there.
So basically, your digit handling code should look like:
if(Character.isDigit(infixExpr.charAt(i)) == true){
if ( ! inNumber ) {
postfix += " ";
}
postfix = postfix + infixExpr.charAt(i);
inNumber = true;
}
And in every if that indicate an operator you should have inNumber = false.
And every place where you add an operator to postfix should look like:
postfix = postfix + " " + s.pop();
Handling parentheses
Your other problem is the handling of ().
First, you put the code that checks for ( and ) inside the if for * and /. Of course, if the character at the i position is * or /, it is not a ( or a ) so this code is never called.
So you should move the if for parentheses outside, to the same level of the if on numbers and operators.
Also, your use of enter is wrong. If you have parenthesis inside parenthesis, like ( 3 + ( 5 + 7 ) ), then at the first ) you will go back all the way to the parenthesis after the 5, which is OK. But then enter will become false and you will not process the external pair correctly. This is also true for (3 + 5 ) * ( 7 + 2 ) because you are not setting enter to true again after the beginning of the program.
Instead of using enter, you should pop what's on the stack and check if it was a (:
if(infixExpr.charAt(i) == '('){
inNumber = false;
s.push(infixExpr.charAt(i));
}
if(infixExpr.charAt(i) == ')'){
inNumber = false;
char popped;
while ( ( popped = s.pop() ) != '(' ) {
postfix = postfix + " " + popped;
}
}
Unpopped operators
Finally, you finish when you completed scanning the input. But at this point you will still have operators waiting on the stack! You have to pop them all and add to postfix. So after the loop you should have:
while ( ! s.isEmpty()) {
postfix += " " + s.pop();
}
Additional remarks:
It would be better and more clear if instead of using all those if statements, you used a switch statement.
There is no point in comparing a boolean expression to true. The proper way to write if (s.isEmpty() == true) is just if (s.isEmpty()), and instead of s.isEmpty() != true use ! s.isEmpty().
You are not doing any syntax checking. I am not sure if that's because this is homework, but in real life you should check that every ( is matched by a ), that every operator has two operands, and also handle negative numbers that may have a - in the beginning.

The issue is that you are not adding spaces. You cannot, however, simply add a space in between each number. You have to make sure the spaces are not being added in between the digits of a whole number. To solve this, I simply added a postfix += " "; after the if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-')and again after if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ). The logic behind this is that once you encounter an operator, you know that everything before the operator was the number. Now when I run the program, the output is 20 2 3 *+2 8 *+5 4. There are still a few spaces that need to be added between the operators, but I'll let you handle that.
Modified code:
if(infixExpr.charAt(i) == '+' || infixExpr.charAt(i) == '-'){
postfix += " ";
...
if(infixExpr.charAt(i) == '*' || infixExpr.charAt(i) == '/' ){
postfix += " ";

here is my code for your answer
#include<stack>
#include<iostream>
using namespace std;
bool high(char a,char b)
{
if(b==' ')
return true;
else if(a==b)
return false;
else if(a=='/')
return true;
else if(a=='*'&&b!='/')
return true;
else if(b=='/')
return false;
else if(a!='/'&&b=='*')
return false;
else if(b=='-')
return true;
else if(a=='-'&&b!='(')
return false;
else if(b=='(')
return true;
else if(a=='(')
return true;
else if(a==')')
return false;
}
main()
{
int k=0;
string s;
stack<char>s1;
s1.push(' ');
char ch;
while(cin>>ch)
{
if(ch=='(')
{
k=1;
s1.push(ch);}
else if(ch>47&&ch<58)
s.push_back(ch);
else if(high(ch,s1.top()))
s1.push(ch);
else if(!high(ch,s1.top())&&ch!=')')
{
while(!s1.empty()&&!high(ch,s1.top()))
{
s.push_back(s1.top());
s1.pop();
}
s1.push(ch);}
else if(ch==')')
{
while(!s1.empty()&&s1.top()!='(')
{
s.push_back(s1.top());
s1.pop();
}
s1.pop();
k=0;
}
}
while(!s1.empty())
{
s.push_back(s1.top());s1.pop();
}
cout<<s;
}

Related

How can I get the password to return back to password request if an invalid password is entered in Java?

I am trying to get the password to return and re-ask for the password if an invalid password is entered. And if a password is invalid 3 consecutive times, the system should terminate.
Is there an issue how I have structured the sequence of the lines of code? Please advise as I am rather new to Java.
public static void main(String []args){
final int MAX=10;
int invalidCount = 0;
final int MIN_Uppercase=1;
int uppercaseCounter=0;
int digitCounter=0;
int specialCounter=0;
System.out.println("Enter the password\n");
Scanner input = new Scanner(System.in);
String password = input.nextLine();
for (int i=0; i < password.length(); i++ ) {
char c = password.charAt(i);
if(Character.isDigit(c))
digitCounter++;
if(Character.isUpperCase(c))
uppercaseCounter++;
if(c == '!' || c == '#' || c == '#' || c == '$' || c == '%' || c == '^' || c == '&' || c == '*' || c == '(' || c == ')' || c == '-' || c == '_' || c == '=' || c == '+'){
specialCounter++;
}
}
if (password.length() >= MAX && uppercaseCounter >= 1 && specialCounter == 1 && (digitCounter == 2 || digitCounter == 3)) {
System.out.println("Valid Password");
}
else {
invalidCount++;
if(password.length() < MAX)
System.out.println("Enter atleast 10 characters");
if (uppercaseCounter < MIN_Uppercase)
System.out.println("Enter at least 1 uppercase character");
if(digitCounter != 2 && digitCounter != 3)
System.out.println("Enter either 2 or 3 digits only");
if(specialCounter != 1)
System.out.println("Password must contain 1 special character");
if (invalidCount == 3)
System.out.println("Maximum tries reached");
System.exit(invalidCount);
}
return;
}
You need to put this entire logic in a while loop that keeps tracks of invalidCount.
The other solution is to put the entire logic in a while loop which is always true and it breaks out of the loop in case correct password is entered.
Also, by seeing the if condition in your code, I would like to point out only the first println statement is inside the if part and not the second println statement.
if (invalidCount == 3)
System.out.println("Maximum tries reached");
System.exit(invalidCount);
but i think you wanted to put it something like this. such that when the count reaches 3, then it should terminate.
if (invalidCount == 3) {
System.out.println("Maximum tries reached");
System.exit(invalidCount);
}
Place the Password prompt into a while loop with a counter, for example:
Scanner userInput = new Scanner(System.in);
int maxPasswordAttempts = 3;
int passwordCounter = 0;
String password = "";
while (password.isEmpty()) {
passwordCounter++;
if (passwordCounter > maxPasswordAttempts) {
System.out.println("Maximum allowable password attempts (" + maxPasswordAttempts
+ ")has been\ncarried out! No longer accepting a passwords!");
System.exit(0);
}
System.out.print("Please enter a password (c to cancel): --> ");
password = userInput.nextLine().trim();
if (password.equalsIgnoreCase("c")) {
System.out.println("Password Entry - CANCELED!");
return;
}
/* Regex from the website:
https://mkyong.com/regular-expressions/how-to-validate-password-with-regular-expression/
Give it a read... */
if (!password.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!##&()–[{}]:;',?/%*~$^+=<>]).{8,20}$")) {
System.out.println();
System.out.println("INVALID PASSWORD! - Secure Password requirements:\n" +
"-------------------------------------------------\n" +
"Password must contain at least one digit [0-9].\n" +
"Password must contain at least one lowercase Latin character [a-z].\n" +
"Password must contain at least one uppercase Latin character [A-Z].\n" +
"Password must contain at least one special character like: ! # # & ( ). %, etc.\n" +
"Password must contain a length of at least 8 characters and a maximum of 20 characters.\n" +
"Try Again...\n");
password = "";
}
}
System.out.println("\nYour VALID password is: " + password);
System.out.println("Now HASH it! :)");

Why does my comparison clause always throw an IllegalArgumentException?

I'm trying to create a calculator method and I want to use mathematical symbols in my case statement but my error checking keeps throwing an error.
I've tried moving my ELSE statements to the bottom in case it was an issue with sequencing somehow. When I add the variable to the end of my error message it appears to assign it correctly.
public static void calculator (double firstNumber, char operation, double secondNumber){
if (operation != '+' || operation != '-' || operation != '*' || operation != '/' || operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
}else{
if(operation == '/' && secondNumber == 0){
throw new IllegalArgumentException("Dividend cannot be zero.");
}else{if(operation == '%' && secondNumber == 0){
throw new IllegalArgumentException("Dividend cannot be zero.");
}else
switch (operation){
case '+': System.out.println("1");
break;
case '-': System.out.println("2");
break;
case '*': System.out.println("3");
break;
....
Example of errors using +, %, and /:
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive.+ at MathUtilites.calculator(MathUtilites.java:39)
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive.% at MathUtilites.calculator(MathUtilites.java:39)
> java.lang.IllegalArgumentException: You must choose a number between 1
> and 5 inclusive./ at MathUtilites.calculator(MathUtilites.java:39)
I am expecting it to just return a number between 1 and 5 which I will later be replacing with actual code.
Like the first comment on your question suggested, you need to replace || with && which will say all of these must be true instead of saying any of these must be true. Alter your code to look like this and it should work:
if (operation != '+' && operation != '-' && operation != '*' && operation != '/' && operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
if (operation != '+' || operation != '-' || operation != '*' || operation != '/' || operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
should be
if (operation != '+' && operation != '-' && operation != '*' && operation != '/' && operation !='%'){
throw new IllegalArgumentException("You must choose a number between 1 and 5 inclusive." + operation);
}
You should look up the boolean algebra related to OR and AND operators.

Java.... Prints 1 error for each character in the input

Im a rookie Java coder, and I am trying to make a very basic username/password program. The username part of it is working fine, but when I get to the password it gives me some weird problems. I figured out that for example when it checks for an Uppercase letter, if it finds one its all good, but if it doesn't, it prints the error message for every single character in the password. It does this with the number check and the length check as well. If any of you guys could explain this to me rather simply since I am still new to java, that would be awesome. Thanks!
do
{
if (count3 >0)
{
System.err.println("- At least 1 Uppercase");
System.err.println("- At least 1 number");
System.err.println("- At least 7 characters long.");
}
regPassword = input.nextLine();
regPasswordLen = regPassword.length();
for(int count = 0; count < regPasswordLen; count++)
{
if(Character.isUpperCase(regPassword.charAt(count)))
regPasswordUppercaseCheck = true;
else
{
System.err.println("Your password did not contain an Uppercase letter");
regPasswordUppercaseCheck = false;
}
if(regPassword.contains("1") || regPassword.contains("2") ||
regPassword.contains("3") || regPassword.contains("4") ||
regPassword.contains("5") || regPassword.contains("6") ||
regPassword.contains("7") || regPassword.contains("8") ||
regPassword.contains("9") || regPassword.contains("0"))
regPasswordNumCheck = true;
else
{
System.err.println("Your password did not contain at least 1 number.");
regPasswordNumCheck = false;
}
if (regPasswordLen >=7)
regPasswordLengthCheck = true;
else
{
System.err.println("Your password did not meet the minimum length requirements.");
regPasswordLengthCheck = false;
}
}
count3++;
}
while(!regPasswordUppercaseCheck || !regPasswordNumCheck || !regPasswordLengthCheck);
System.out.println("test");
You used same variable every time for "if and else" for every different char i.e. regPasswordUppercaseCheck, if every char of your input is in uppercase except the last char, the variable will contain false.
I think you use count3 for making sure that inner code will run single time but if while goes false and count3 condition is remain true then code will stuck in a infinite loop.
Use
while(regPasswordUppercaseCheck && regPasswordNumCheck && regPasswordLengthCheck); for simplicity.
A few things you can change in your program.
do
{
if (count3 >0)
{
System.err.println("- At least 1 Uppercase");
System.err.println("- At least 1 number");
System.err.println("- At least 7 characters long, but no more than 15 characters.");
}
regPassword = input.nextLine();
regPasswordLen = regPassword.length();
// this check only needs to happen once per password, no need to check it in the for loop. You also specified that the length should not exceed 15 characters, so I threw that in as well
if (regPasswordLen < 7 || regPasswordLen > 15)
System.err.println("Your password did not meet the length requirements.");
// by default, we set these flags to false, and only make them true if the requirements are satisfied
regPasswordUppercaseCheck = false;
regPasswordNumCheck = false;
for(int count = 0; count < regPasswordLen; count++)
{
// store the value of regPassword.charAt(count) in a local variable for reusability
char current = regPassword.charAt(count);
if(Character.isUpperCase(current))
regPasswordUppercaseCheck = true;
// checks if the character is a digit or not
if(current >= '0' && current <= '9')
regPasswordNumCheck = true;
}
if (!regPasswordNumCheck)
System.err.println("Your password did not contain at least 1 number.");
if (!regPasswordUppercaseCheck)
System.err.println("Your password did not contain an Uppercase letter");
count3++;
}
while(!regPasswordUppercaseCheck || !regPasswordNumCheck || !regPasswordLengthCheck);
your checking for uppercase is not done right because the loop
for(int count=0;count<regPasswordLength;count++) should not contain the checking if the password contains a number nor the checking if the password is longer than 7 characters so the loop should look like this
for (int count = 0; count < regPasswordLen; count++) {
if (Character.isUpperCase(regPassword.charAt(count)))
{regPasswordUppercaseCheck = true;break;}
}
i use break here to get out of the loop the moment i found that password contains an uppercase after some modifications your code can look like this
do {
if (count3 > 0) {
System.err.println("- At least 1 Uppercase");
System.err.println("- At least 1 number");
System.err
.println("- At least 7 characters long, but no more than 15 characters.");
}
regPassword = input.nextLine();
regPasswordLen = regPassword.length();
for (int count = 0; count < regPasswordLen; count++) {
if (Character.isUpperCase(regPassword.charAt(count)))
{regPasswordUppercaseCheck = true;break;}
}
if(regPasswordUppercaseCheck==false){
System.err
.println("Your password did not contain an Uppercase letter");
regPasswordUppercaseCheck = false;
}
regPasswordNumCheck = regPassword.contains("1") || regPassword.contains("2")
|| regPassword.contains("3")
|| regPassword.contains("4")
|| regPassword.contains("5")
|| regPassword.contains("6")
|| regPassword.contains("7")
|| regPassword.contains("8")
|| regPassword.contains("9")
|| regPassword.contains("0");
if(regPasswordNumCheck==false) {
System.err
.println("Your password did not contain at least 1 number.");
regPasswordNumCheck = false;
}
if (regPasswordLen >= 7)
regPasswordLengthCheck = true;
else {
System.err
.println("Your password did not meet the minimum length requirements.");
regPasswordLengthCheck = false;
}
count3++;
} while (!regPasswordUppercaseCheck || !regPasswordNumCheck
|| !regPasswordLengthCheck);
System.out.println("test");

How to turn a user given String into Pig Latin?

Im trying to turn a string taken from the user into Pig Latin. I cannot use any special classes, methods, or arrays. I can only use a Scanner to create a object to take the string from the user and .length and .charAt, in addition to any type of looping. (Also cannot use switch statements or the break keyword)
Here is an example of what my output is suppose to be:
Enter a line of text: this is a test.
Input : this is a line of text.
Output: his-tay is-way a-way ine-lay of-way ext-tay.
Here is my code, I can only get my code to work with one word and it must have a space at the end. Only one loop works at a time depending on the loop. Im not sure what to do if I get an entire String.
I know that when the user enters a space that signals a new word, and when they enter a period, that signals the ending.
I had a hard time understanding your code. (It looks like you are trying to do it two ways at once?) Regardless, I believe I was able to understand your question. Here is a compilable and runnable example:
import java.util.Scanner;
public class PigLatin
{
public static void main(String[] args)
{
System.out.print("Enter a line of text: ");
Scanner keyboard = new Scanner(System.in);
String text = keyboard.nextLine();
System.out.println("\nInput: " + text);
System.out.print("Output: ");
if (text != null && text.length() > 0)
{
int i = 0;
// this iterates through the whole string, stopping at a period or
// the end of the string, whichever is closer
while (i < text.length() && text.charAt(i) != '.')
{
// these three variables only exist in this code block,
// so they will be re-initialized to these values
// each time this while loop is executed
char first = '\0'; // don't worry about this, I just use this value as a default initializer
boolean isFirst = true;
boolean firstIsVowel = false;
// each iteration of this while loop should be a word, since it
// stops iterating when a space is encountered
while (i < text.length()
&& text.charAt(i) != ' '
&& text.charAt(i) != '.')
{
// this is the first letter in this word
if (isFirst)
{
first = text.charAt(i);
// deal with words starting in vowels
if (first == 'a' || first == 'A' || first == 'e' || first == 'E'
|| first == 'i' || first == 'I' || first == 'o' || first == 'O'
|| first == 'u' || first == 'U')
{
System.out.print(first);
firstIsVowel = true;
}
// make sure we don't read another character as the first
// character in this word
isFirst = false;
}
else
{
System.out.print(text.charAt(i));
}
i++;
}
if (firstIsVowel)
{
System.out.print("-tay ");
}
else if (first != '\0')
{
System.out.print("-" + first + "ay ");
}
i++;
}
System.out.print('\n'); //for clean otuput
}
}
}
There are a few comments in there that might help guide you through my logic. This is almost definitely not the most efficient way to do this (even with your limitations), as I only whipped it up as a example of the type of logic you could use.
You could break it up into words, then process the current word when you hit a space or period:
System.out.print("Enter a line of text: ");
Scanner keyboard = new Scanner(System.in);
String text = keyboard.nextLine();
System.out.println("\nInput: " + text);
System.out.print("Output: ");
String curWord = "";
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == ' ' || text.charAt(i) == '.') {
if (curWord.charAt(0) == 'a' || curWord.charAt(0) == 'e' ||
curWord.charAt(0) == 'i' || curWord.charAt(0) == 'o' ||
curWord.charAt(0) == 'u') {
System.out.print(curWord + "-way ");
} else {
for (int j = 1; j < curWord.length(); j++) {
System.out.print(curWord.charAt(j);
}
System.out.print("-" + curWord.charAt(0) + "ay ");
//System.out.print(curWord.substring(1)+"-"+curWord.charAt(0)+"ay ");
}
curWord = "";
} else {
curWord += text.charAt(i);
}
}

Validate a string contains only certain characters in java

Ok, what I am trying to do is take a user input in infix notation and translate it to postfix and then evaluate it. I have that already completed.
What I am struggling with, is for the user input I need to validate that it only contains the following: (), 0-9, +, -, *, /, %
Each character will be separated by a space, so here is a potential valid input:
( 3 + 4 ) * 5 / ( 6 - 7 )
I have created an InvalidCharacterException that I wish to throw if the user string contains anything other than those characters.
Here is what an invalid input would look like:
3 - 5 ^ 5
The ^ would be an invalid character and then I would throw new InvalidCharacterException and ask for a new input.
I will also say I have looked at a ton of regex samples, and to be honest I don't understand what they're doing.
EDIT:
Ok, this is what I ended up implementing because I don't really understand anything else. Any advice on a simpler way?
for(int i = 0; i <= infix.length(); i++){
if(infix.charAt(i) == '(' || infix.charAt(i) == ')' || infix.charAt(i) =='+'
|| infix.charAt(i) =='-' ||infix.charAt(i) == '*' ||infix.charAt(i) == '/'
||infix.charAt(i) == '%' ||infix.charAt(i) ==' ' ||infix.charAt(i) == '0'
||infix.charAt(i) == '1' || infix.charAt(i) =='2' || infix.charAt(i) =='3'
||infix.charAt(i) == '4' ||infix.charAt(i) == '5' ||infix.charAt(i) == '6'
||infix.charAt(i) == '7' || infix.charAt(i) =='8' ||infix.charAt(i) == '9'){
}else{
throw new InvalidCharacterException(infix.charAt(i));
}
}
Infix is the variable name of my user input as a StringBuffer.
You can use a Scanner to validate your string:
Scanner scanner = new Scanner(string);
String validationResult = scanner.findInLine("[^0-9()+\\-*\\/%]+");
if (validationResult != null) {
// Invalid character found.
throw new InvalidCharacterException("Invalid character: " + validationResult);
}
The findInLine method returns a String with the characters that match the regex and the regex looks for any character not valid in your validation. The findInLine only returns a non null String when there are any invalid characters in the String.
I would suggest you use a Scanner (for an example) and then loop over each character (in each token) and throw your Exception if your criteria are met (e.g. look at Character.isDigit) or just write your own method to test against acceptable characters (e.g. is char is contained in"()0123456789+-*/%").
In your code this is probably better because it does the same thing.
Btw it probably should be i < infix.length() not <=
for(int i = 0; i < infix.length(); i++){
char x = infix.charAt(i);
if(!(Character.isDigit(x) || x == '/' || x == '*' ||
x == '+'|| x== '-' || x=='%' || x == '\n'))
throw new InvalidCharacterException(x);
/* what you want to do if valid*/
}

Categories

Resources