Valid parentheses in Java - java

Code:
public static void main(String[] args) {
Arrays.asList("a+(b*c)-2-a", "(a+b*(2-c)-2+a)*2", "(a*b-(2+c)", "2*(3-a))", ")3+b*(2-c)(")
.stream().forEach((expression) -> {
if (replaceAll(expression, "[(]") == replaceAll(expression, "[)]")) {
System.out.println("correct");
} else {
System.out.println("incorrect");
}
});
}
private static int replaceAll(String word, String regex) {
int count = word.length() - word.replaceAll(regex, "").length();
return count;
}
I have to check if the expression is valid or not. What determine if an expression is valid or not are the parentheses. If it's self closed, is valid, otherwise, not.
My code is almost correct, it's printing:
correct
correct
incorrect
incorrect
correct
But it must print
correct
correct
incorrect
incorrect
incorrect -> the last expression isn't valid.

You need not only to check if the number of opening parentheses matches the number of closed, but also if each closing parenthesis goes after opening one which isn't "closed" yet:
static boolean checkParentheses(String s) {
int opened = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(')
opened++;
else if (s.charAt(i) == ')') {
if (opened == 0) // means that all parentheses are "closed" yet
return false;
opened--;
}
}
return opened == 0;
}
If you strictly need regex to be involved, do the following:
static boolean checkParentheses(String s) {
// capture a text starting with one opening parenthesis,
// ending with one closing and having no parentheses inside
Pattern p = Pattern.compile("\\([^()]*\\)");
Matcher m;
while ((m = p.matcher(s)).find())
s = m.replaceAll("");
return !(s.contains("(") || s.contains(")"));
}

Your issue is that it's not enough just to count parentheses; you also need to spot where a ')' comes too early. For example ")(" is not valid even though there are an equal number of opening and closing parentheses.
One approach is to keep a count. Start at zero. Each time you see '(', count++. Each time you see ')', count--.
After a decrement, if(count<0) the input is invalid.
At the end of input, if(count!0) the input is invalid.
It's been pointed out that this can't be done in a single regex. That's because a regex represents a finite state machine. count could in principle increase infinitely.
If you pick a maximum nesting depth, you can write a regex to check it. For example, for a maximum depth of 3:
x*(<x*(<x*(<x*>)*x*>)*x*>)*x*
(I've used 'x' instead of arbitrary chars here, for readability. Replace it with [^<>] to actually match other chars. I've also used <> instead of \(\) again for readability. The () here are for grouping.).
You can always make it work one level deeper by replacing the x* in the middle with x*(<x*>)*x* -- but you can never made a regex that doesn't stop working at a certain depth.
An alternative method is closer to what a real statement parser would do with nested structures: recurse. Something like (pseudocode):
def consumeBlock() {
switch(next char)
case end-of-input
throw error -- reached end of input inside some parentheses
case '('
consumeBlock() -- go down a nesting level
break;
case ')'
return -- go up a nesting level
default
It's an uninteresting character. Do nothing.
(a real parser compiler would do something more interesting)
}
Here consumeBlock() assumes you've just consumed a '(' and you intend to read until its pair.
Some of your inputs don't begin with a '(', so prime it by first appending a ')' to the end, as the pair to a "silent" ')' you're saying it's already consumed.
The pseudocode already shows that if you hit end-of-input mid-block, it's invalid input. Also if you are not at end-of-input when the top-level call to consumeBlock() returns, it's invalid input.

You could go through it char by char and using a counter to tell the parenthesis level in the statement.
boolean valid = true;
int level = 0;
for(int i=0; i < expr.length(); i++) {
if(expr.charAt(i) == '(') level++;
if(expr.charAt(i) == ')') level--;
if(level < 0) { // ) with no (
valid = false;
break;
}
}
if(level > 0) valid = false; // ( with no )
return valid; // true if level returned to 0

Related

How to make sure the user only inputs 1s and 0s?

I have this loop that keeps the user stuck inputting values until he/she, inputs something valid, in this case it has to be binary numbers that must be the size of a certain type of variable. Nonetheless, I don't know how to make the loop continue in the case that the user inputs a number made up of something different aside from 1s and 0s.
I was thinking of using string.contains(), but that cannot account for every number. Here's my loop:
while((double)inputStr.length() != table.getNumberOfVariables() ||
inputStr.replaceAll("\\D","").length() != inputStr.length() ||
Double.parseDouble(inputStr) > 1){
This line: Double.parseDouble(inputStr) > 1 was supposed to accomplish that, but I'm dealing with decimal numbers, so if the input is 10 or 100, they're rendered invalid.
In your case, rather than using \D in your regex (anything that's not a digit), you must be more specific: [^01] (meaning: anything not a zero or one).
while((double)inputStr.length() != table.getNumberOfVariables() ||
inputStr.replaceAll("[^01]","").length() != inputStr.length() ||
Double.parseDouble(inputStr) > 1){
It doesn't win you a prize for nice code though, because it is hard for the reader of this code to find out what you are doing. It's better to turn what you're doing into a method with a clear name, like:
public static boolean containsOnly(String s, String only) {
for (int i = 0; i < s.length(); i++) {
if (only.indexOf(s.charAt(i)) == -1)
return false;
}
return true;
}
As it happens, the Apache commons-lang3 library has such a method in it: StringUtils.containsOnly. They have many methods for String manipulation that are clearer and often much faster than using regexes.
You can use a regular expression to validate the binary string:
String s = "0101110";
if (s.matches("[01]++")) {
System.out.println("ok");
} else {
System.out.println("invalid");
}

Stack, Parentheses Matching [duplicate]

This question already has answers here:
Handling parenthesis while converting infix expressions to postfix expressions
(2 answers)
Closed 5 years ago.
So I'm working on some homework with PostFix and Infix Expressions. I'm running into a bit of a problem and can't seem to find where I'm having the issue. I can get the Infix to Postfix working...for the most part. Some of the equations I'm getting a ( or ) printed when I don't want it to be printed. Also when I have no matching parentheses I don't get an error like I want it to.
public String Infix(String equation) throws Exception{
Stack stack=new Stack();
boolean parensMatch=false;
int priority=0;
String temp="";
for(int i=0; i<equation.length(); i++){
char c=equation.charAt(i);
//if the character is equal to left paren, push
if(c=='('){
stack.push(c);
}
//if the character is equal to right paren, we start popping until we find a match
else if(c==')'){
try{
while(stack.peek()!='('){
temp+=stack.pop();
}
if(stack.peek()=='('){
char ch=stack.pop();
parensMatch=true;
}
if(parensMatch==false){
throw new Exception("Parens Not Match Error");
}
}catch(Exception e){
System.out.println(e);
}
parensMatch=false;
}
//if the character is equal to an operator, we do some extra work
//to figure out what is going to happen
else if(c=='+' || c=='-' || c=='*' || c=='/' || c=='^'){
char top=stack.peek();
if(top=='^')
priority=2;
else if(top=='*' || top=='/')
priority=1;
else
priority=0;
if(priority==2){
if(c=='*' || c=='/'){
temp+=stack.pop();
}
else if(c=='+' || c=='-'){
temp+=stack.pop();
}
else{
temp+=stack.pop();
}
}
else{
if(c=='*' || c=='/'){
temp+=stack.pop();
stack.push(c);
}
else if(c=='+' || c=='-'){
stack.push(c);
}
else{
stack.push(c);
}
}
}
//if the character is a space, we ignore it and move on
else if(c==' '){
;
}
//if the character is a letter, we add it to the string
else{
temp+=c;
}
}
int len = stack.size();
for (int j = 0; j < len; j++)
temp+=stack.pop();
return temp;
}
This is my Infix to Postfix method
(((A + B) - (C - D)) / (E - F)) This is one of the expressions that I need to solve, and AB+CD--(EF-/ is what I get when it prints to the screen. ((A is another, this one should give me an error but A(( is printed to the screen.
I have been running the debug for quite a while and can't seem to get anywhere.
Any help would be very helpful. I know it has something to with the code posted but I can't find the logic error. Thanks in advance!
So I added a new function to help with matching parens that I think will be useful. It takes the equation and just counts to see if they match or not.
public static int matchingParens(String equation){
int match=0;
for(int i=0; i<equation.length(); i++){
char c=equation.charAt(i);
if(c=='(')
match++;
else if(c==')')
match--;
else
;
}
return match;
}
To validate if parenthesis are all matched up, you can run through your String input of the math expression with a counter of initial value of 0, and if you find a (, increment your counter by 1, and if you find a ), decrement your counter by 1. If the counter ever reaches -1, break out, as it isn't a valid parenthesis match. In the end, you should have the counter's value as 0. If not, you have a mismatched parenthesis.
For the infix to postfix case, here's a standard algorithm:
Define a stack
Go through each character in the string
If it is between 0 to 9, append it to output string.
If it is left brace push to stack
If it is operator *,+,- or / then
If the stack is empty push it to the stack
If the stack is not empty then start a loop:
If the top of the stack has higher precedence
Then pop and append to output string
Else break
Push to the stack
If it is right brace then
While stack not empty and top not equal to left brace
Pop from stack and append to output string
Finally pop out the left brace.
Well I would like give you some "software engineering" tip, which in the end can solve your problem and you can learn a lot by doing it "nice".
Mathematical expression, no matter if you write them in pre, in, post order, looks always the same, if you store them in some tree structure.
Then, if you want to print that tree structure into String, you just go through the whole tree, and it varies only in the moment (and additional braces for some cases), when you write it to that string.
Preorder do it when you first go into that node, Inorder when you finished left child and Postorder, if you do it when you leaving that node.
My advice :
Class : Expression, UnaryExpression extends Expression, BinaryExpression extedns Expression and then you can make numbers and operators : Add extends BinaryExpression etc.
Then you should have class Tree, which stores the Expression root and it has methods printPreOrder(), printInOrder(), printPostOrder()
To create that tree, it would be really nice to use a Builder pattern which can be used like this :
public class Director {
private IExpressionBuilder builder;
public ArithmeticExpression construct(String text){
for (int i=0;i<text.length();i++){
if (text.charAt(i) == '+'){
builder.buildAddOperator();
}
...
}
}
And then you create concrete Builder classes, which look like this :
public class InOrderBuilder implements IExpressionBuilder {
public void buildAddOperator() {
...
}
....
}

String not populating properly

I am writing a program that is going to read a string from a file, and then remove anything that isn't 1-9 or A-Z or a-z. The A-Z values need to become lowercase. Everything seems to run fine, I have no errors, however my output is messed up. It seems to skip certain characters for no reason whatsoever. I've looked at it and tweaked it but nothing works. Can't figure out why it is randomly skipping certain characters because I believe my if statements are correct. Here is the code:
String dataIn;
int temp;
String newstring= "";
BufferedReader file = new BufferedReader(new FileReader("palDataIn.txt"));
while((dataIn=file.readLine())!=null)
{
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
i++;
}
System.out.println(newstring);
}
So to give you an example, the first string I read in is :
A sample line this is.
The output after my program runs through it is this:
asmlietis
So it is reading the A making it lowercase, skips the space like it is suppose to, reads the s in, but then for some reason skips the "a" and the "m" and goes to the "p".
You're incrementing i in the each of the blocks as well as in the main loop "header". Indeed, because you've got one i++; in an else statement for the last if statement, you're sometimes incrementing i twice during the loop.
Just get rid of all the i++; statements other than the one in the for statement declaration. For example:
newstring="";
for(int i=0;i<dataIn.length();i++)
{
temp=(int)dataIn.charAt(i);
if(temp>46&&temp<58)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>96&&temp<123)
{
newstring=newstring+dataIn.charAt(i);
}
if(temp>64&&temp<91)
{
newstring=newstring+Character.toLowerCase(dataIn.charAt(i));
}
}
I wouldn't stop editing there though. I'd also:
Use a char instead of an int as the local variable for the current character you're looking at
Use character literals for comparisons, to make it much clearer what's going on
Use a StringBuilder to build up the string
Declare the variable for the output string for the current line within the loop
Use if / else if to make it clear you're only expecting to go into one branch
Combine the two paths that both append the character as-is
Fix the condition for numbers (it's incorrect at the moment)
Use more whitespace for clarity
Specify a locale in toLower to avoid "the Turkey problem" with I
So:
String line;
while((line = file.readLine()) != null)
{
StringBuilder builder = new StringBuilder(line.length());
for (int i = 0; i < line.length(); i++) {
char current = line.charAt(i);
// Are you sure you want to trim 0?
if ((current >= '1' && current <= '9') ||
(current >= 'a' && current <= 'z')) {
builder.append(current);
} else if (current >= 'A' && current <= 'Z') {
builder.append(Character.toLowerCase(current, Locale.US));
}
}
System.out.println(builder);
}

Java - See if a string contains any characters in it

The problem i'm having is when i check to see if the string contains any characters it only looks at the first character not the whole string. For instance I would like to be able to input "123abc" and the characters are recognized so it fails. I also need the string to be 11 characters long and since my program only works with 1 character it cannot go any further.
Here is my code so far:
public static int phoneNumber(int a)
{
while (invalidinput)
{
phoneNumber[a] = myScanner.nextLine();
if (phoneNumber[a].matches("[0-9+]") && phoneNumber[a].length() == 11 )
{
System.out.println("Continue");
invalidinput = false;
}
else
{
System.out.print("Please enter a valid phone number: ");
}
}
return 0;
}
For instance why if i take away the checking to see the phoneNumber.length() it still only registers 1 character so if i enter "12345" it still fails. I can only enter "1" for the program to continue.
If someone could explain how this works to me that would be great
Your regex and if condition is wrong. Use it like this:
if ( phoneNumber[a].matches("^[0-9]{11}$") ) {
System.out.println("Continue");
invalidinput = false;
}
This will only allow phoneNumber[a] to be a 11 character long comprising only digits 0-9
The + should be outside the set, or you could specifically try to match 11 digits like this: ^[0-9]{11}$ (the ^ and $ anchor the match to the start and end of the string).
You need to put the "+" after the "]" in your regex. So, you would change it to:
phoneNumber[a].matches("[0-9]+")
Why not try using a for loop to go through each character?
Like:
public static int phoneNumber(int a)
{
while (invalidinput)
{
int x = 0;
for(int i = 0; i < phoneNumber[a].length(); i++)
{
char c = phoneNumber[a].charAt(i);
if(c.matches("[0-9+]")){
x++;
}
}
if (x == phoneNumber[a].length){
System.out.println("Continue");
invalidinput = false;
}
else
{
System.out.print("Please enter a valid phone number: ");
}
}
return 0;
}
Are the legal characters in your phone numbers 0..9 and +? If so, then you should use the regular expression [0-9+]*, which matches zero or more legal characters. (If not, you probably meant [0-9]+.) Also, you can use [0-9+]{11} instead of your explicit check for a length of 11.
The reason that your current code fails, is that String#matches() does not check whether the regular expression matches part of the string, but whether it matches all of the string. You can see this in the JavaDoc, which points you to Matcher#matches(), which "Attempts to match the entire region against the pattern."

Finding Palindromes in a word list

I'm working on a program for Java on how to find a list of palindromes that are embedded in a word list file. I'm in an intro to Java class so any sort of help or guidance will be greatly appreciated!
Here is the code I have so far:
import java.util.Scanner;
import java.io.File;
class Palindromes {
public static void main(String[] args) throws Exception {
String pathname = "/users/abrick/resources/american-english-insane";
File dictionary = new File(pathname);
Scanner reader = new Scanner(dictionary);
while (reader.hasNext()) {
String word = reader.nextLine();
for (int i = 0; i > word.length(); i++) {
if (word.charAt(word.indexOf(i) == word.charAt(word.indexOf(i)) - 1) {
System.out.println(word);
}
}
}
}
}
There are 3 words that are 7 letters or longer in the list that I am importing.
You have a few ways to solve this problem.
A word is considered a palindrome if:
It can be read the same way backwards as forwards.
The first element is the same as the last element, up until we reach the middle.
Half of the word is the same as the other half, reversed.
A word of length 1 is trivially a palindrome.
Ultimately, your method isn't doing much of that. In fact, you're not doing any validation at all - you're only printing the word if the first and last character match.
Here's a proposal: Let's read each end of the String, and see if it's a palindrome. We have to take into account the case that it could potentially be empty, or be of length 1. We also want to get rid of any white space in the string, as that can cause errors on validation - we use replaceAll("\\s", "") to solve that.
public boolean isPalindrome(String theString) {
if(theString.length() == 0) {
throw new IllegalStateException("I wouldn't expect a word to be zero-length");
}
if(theString.length() == 1) {
return true;
} else {
char[] wordArr = theString.replaceAll("\\s", "").toLowerCase().toCharArray();
for(int i = 0, j = wordArr.length - 1; i < wordArr.length / 2; i++, j--) {
if(wordArr[i] != wordArr[j]) {
return false;
}
}
return true;
}
}
I'm assuming that you're reading in strings. Use string.toCharArray() to convert each string to a char[]. Iterate through the character array using a for loop as follows: on iteration 1, if the first character is equal to the last character, then proceed to the next iteration, else return false. On iteration 2, if the second character is equal to the second-to-last character then proceed to the next iteration, else return false. And so on, until you reach the middle of the string, at which point you return true. Be careful of off-by-one errors; some strings will have an even length, some will have an odd length.
If your palindrome checker is case insensitive, then use string.toLowerCase().toCharArray() to preprocess the character array.
You can use string.charAt(i) instead of string.toCharArray() in the for loop; in this case, if the palindrome checker is case insensitive then preprocess the string with string = string.toLowerCase()
Let's break the problem down: In the end, you are checking if the reverse of the word is equal to the word. I'm going to assume you have all of the words stored in an array called wordArray[].
I have some code for getting the reverse of the word (copied from here):
public String reverse(String str) {
if ((null == str) || (str.length() <= 1)) {
return str;
}
return new StringBuffer(str).reverse().toString();
}
So, now we just need to call that on every word. So:
for(int count = 0; count<wordArray.length;count++) {
String currentWord = wordArray[count];
if(currentWord.equals(reverse(currentWord)) {
//it's a palendrome, do something
}
}
Since this is homework, i'll not supply you with code.
When i code, the first thing i do is take a step back and ask myself,
"what am i trying to get the computer to do that i would do myself?"
Ok, so you've got this huuuuge string. Probably something like this: "lkasjdfkajsdf adda aksdjfkasdjf ghhg kajsdfkajsdf oopoo"
etc..
A string's length will either be odd or even. So, first, check that.
The odd/even will be used to figure out how many letters to read in.
If the word is odd, read in ((length-1)/2) characters.
if even (length/2) characters.
Then, compare those characters to the last characters. Notice that you'll need to skip the middle character for an odd-lengthed string.
Instead of what you have above, which checks the 1st and 2nd, then 2nd and 3rd, then 3rd and fourth characters, check from the front and back inwards, like so.
while (reader.hasNext()) {
String word = reader.nextLine();
boolean checker = true;
for (int i = 0; i < word.length(); i++) {
if(word.length()<2){return;}
if (word.charAt(i) != word.charAt(word.length()-i) {
checker = false;
}
}
if(checker == true)
{System.out.println(word);}
}

Categories

Resources