Regex not valid when trying to invalidate alpha's and non-zeros - java

Wrote a method which takes in a String and checks to see the follow conditions:
If String is "quit", it will terminate the program.
If the String is any value other than an integer, it should return "Invalid input ".
Any negative integers and also 0 should return "Invalid input".
However, when I passed in 10, it returned as "Invalid input"?
Please advise:
public static String validate(String input) {
Pattern pattern = Pattern.compile(".*[^1-9].*");
StringBuilder results = new StringBuilder();
if (input.equals("quit")) {
System.exit(1);
} else if (!pattern.matcher(input).matches() == false) {
results.append("Invalid input ");
results.append("'");
results.append(input);
results.append("'");
}
return results.toString();
}
What's wrong with what I am doing?

You should write a pattern of what you expect instead of what you're not.
As describe what you want is always simpler that describe the rest of it.
So you expect :
Pattern acceptPattern = Pattern.compile("[1-9][0-9]*");
You may consider make you conditional expression simpler and correct by not using both ! and == false at the same time:
Which will make :
if (!acceptPattern .matcher(input).matches()) {//Invalid input code}
or
if (acceptPattern .matcher(input).matches() == false) {//Invalid input code}
note :
You write if(!A == false) => if(A == true) => if(A) but which was the inverse

It looks like you want to match one or more digits, where the first one is not a zero.
[1-9]\d*
If you want to force it to be the entire string, you can add anchors, like this:
^[1-9]\d*$

Your regex string doesn't allow for the presence of a zero (not just a lone zero).
That is, the string ".*[^1-9].*" is looking for "any number of characters, something that isn't 1-9, and any number of characters". When it finds the zero, it gives you your incorrect result.
Check out What is the regex for "Any positive integer, excluding 0" for how to change this.
Probably the most helpful solution on that page is the regex [0-9]*[1-9][0-9]* (for a valid integer). This allows for leading zeros and/or internal zeros, both of which could be present in a valid integer. In using Matcher#matches you also ensure that this regex matches the whole input, not just part of it (without the need to add in beginning and end anchors -- ^$).
Also, the line else if (!pattern.matcher(input).matches() == false) could be made a lot more clear.... maybe try else if (pattern.matcher(input).matches()) instead?

Related

Big palindrome of even length - Wrong Answer

I have been taking the test on Codility, and trying this exercise:
https://app.codility.com/programmers/trainings/4/disappearing_pairs/
A string S containing only the letters "A", "B" and "C" is given. The string can be transformed by removing one occurrence of "AA", "BB" or "CC".
Transformation of the string is the process of removing letters from it, based on the rules described above. As long as at least one rule can be applied, the process should be repeated. If more than one rule can be used, any one of them could be chosen.
Write a function:
class Solution { public String solution(String S); }
that, given a string S consisting of N characters, returns any string that can result from a sequence of transformations as described above.
For example, given string S = "ACCAABBC" the function may return "AC", because one of the possible sequences of transformations is as follows:
Also, given string S = "ABCBBCBA" the function may return "", because one possible sequence of transformations is:
Finally, for string S = "BABABA" the function must return "BABABA", because no rules can be applied to string S.
Write an efficient algorithm for the following assumptions:
the length of string S is within the range [0..50,000];
string S is made only of the following characters: "A", "B" and/or "C".
Here is the code that I tried with a score of 83:
public String solution(String S) {
boolean notAA = false;
boolean notBB = false;
boolean notCC = false;
while(S.length()==0 || true){
if (S.contains("AA")){
S = S.replace("AA", "");
} else {
notAA = true;
}
if(S.contains("BB")){
S = S.replace("BB", "");
} else {
notBB = true;
}
if(S.contains("CC")){
S = S.replace("CC", "");
} else {
notCC = true;
}
if(notAA && notBB && notCC){
break;
}
}
return S;
}
I could not obtain the 100% score because of this:
even_palindrome1 big palindrome of even length
✘WRONG ANSWER got CACABACABABCBACBACBA.. expected ""
Codility doesn't show me the string example or any other information.
I was reading and reviewing but I still do not understand why I am not getting the right output. My assumption is when I delete the first combination of letters, the string needs to be in a specific state or a specific combination of letters to work correctly and the problem is the palindrome even string.
But, if my assumption is correct, I don't really understand the real cause or root reason for this.
Thanks in advance for your help.
You should reset notAA, notBB and notCC inside your loop.
Consider, for example, ABCCBA. In your first pass, notAA and notBB are set to true, leaving ABBA. In the second pass, notAA and notCC are set to true, leaving AA. Your program would then break out with an available pair because all three conditions are set to true.
You have to set notAA, notBB and notCC to false inside the loop, not before it. The way you are doing it, you find all three, you end the loop.
Say S is ABCCBA.
You set notAA and notBB to true, because AA and BB cannot be found; then you replace CC, giving you ABBA.
Next loop, you set notAA to true again, remove BB, producing AA, and set notCC to true. Now all three are true (since notBB remained true since the first iteration), and you break the loop.
The result is AA, which should have reduced further; but because the program thought there was no AA, but it appeared after notAA was set, you get the wrong value.
In fact, this can be simplified: you just need a single flag changed, which starts before the loop as true; then use while (changed). At the top of the loop, set it to false, and set it to true every time you successfully replace a substring. You do not need three separate ones, since they all do effectively the same job.

finding the middle index of a substring when there are duplicates in the string

I was working on a Java coding problem and encountered the following issue.
Problem:
Given a string, does "xyz" appear in the middle of the string? To define middle, we'll say that the number of chars to the left and right of the "xyz" must differ by at most one
xyzMiddle("AAxyzBB") → true
xyzMiddle("AxyzBBB") → false
My Code:
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)result=false;
if(str.length()==3 && str.equals("xyz"))result=true;
for(int j=0;j<str.length()-3;j++){
if(str.substring(j,j+3).equals("xyz")){
String rightSide=str.substring(j+3,str.length());
int rightLength=rightSide.length();
String leftSide=str.substring(0,j);
int leftLength=leftSide.length();
int diff=Math.abs(rightLength-leftLength);
if(diff>=0 && diff<=1)result=true;
else result=false;
}
}
return result;
}
Output I am getting:
Running for most of the test cases but failing for certain edge cases involving more than once occurence of "xyz" in the string
Example:
xyzMiddle("xyzxyzAxyzBxyzxyz")
My present method is taking the "xyz" starting at the index 0. I understood the problem. I want a solution where the condition is using only string manipulation functions.
NOTE: I need to solve this using string manipulations like substrings. I am not considering using list, stringbuffer/builder etc. Would appreciate answers which can build up on my code.
There is no need to loop at all, because you only want to check if xyz is in the middle.
The string is of the form
prefix + "xyz" + suffix
The content of the prefix and suffix is irrelevant; the only thing that matters is they differ in length by at most 1.
Depending on the length of the string (and assuming it is at least 3):
Prefix and suffix must have the same length if the (string's length - the length of xyz) is even. In this case:
int prefixLen = (str.length()-3)/2;
result = str.substring(prefixLen, prefixLen+3).equals("xyz");
Otherwise, prefix and suffix differ in length by 1. In this case:
int minPrefixLen = (str.length()-3)/2;
int maxPrefixLen = minPrefixLen+1;
result = str.substring(minPrefixLen, minPrefixLen+3).equals("xyz") || str.substring(maxPrefixLen, maxPrefixLen+3).equals("xyz");
In fact, you don't even need the substring here. You can do it with str.regionMatches instead, and avoid creating the substrings, e.g. for the first case:
result = str.regionMatches(prefixLen, "xyz", 0, 3);
Super easy solution:
Use Apache StringUtils to split the string.
Specifically, splitByWholeSeparatorPreserveAllTokens.
Think about the problem.
Specifically, if the token is in the middle of the string then there must be an even number of tokens returned by the split call (see step 1 above).
Zero counts as an even number here.
If the number of tokens is even, add the lengths of the first group (first half of the tokens) and compare it to the lengths of the second group.
Pay attention to details,
an empty token indicates an occurrence of the token itself.
You can count this as zero length, count as the length of the token, or count it as literally any number as long as you always count it as the same number.
if (lengthFirstHalf == lengthSecondHalf) token is in middle.
Managing your code, I left unchanged the cases str.lengt<3 and str.lengt==3.
Taking inspiration from #Andy's answer, I considered the pattern
prefix+'xyz'+suffix
and, while looking for matches I controlled also if they respect the rule IsMiddle, as you defined it. If a match that respect the rule is found, the loop breaks and return a success, else the loop continue.
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)
result=false;
else if(str.length()==3 && str.equals("xyz"))
result=true;
else{
int preLen=-1;
int sufLen=-2;
int k=0;
while(k<str.lenght){
if(str.indexOf('xyz',k)!=-1){
count++;
k=str.indexOf('xyz',k);
//check if match is in the middle
preLen=str.substring(0,k).lenght;
sufLen=str.substring(k+3,str.lenght-1).lenght;
if(preLen==sufLen || preLen==sufLen-1 || preLen==sufLen+1){
result=true;
k=str.length; //breaks the while loop
}
else
result=false;
}
else
k++;
}
}
return result;
}

Java - using ".contains" in the opposite manner

I want to be able to print a string that doesn't contain the words "Java", "Code" or "String", though I am unsure on how to achieve this as I thought this would be achieved by using '!' (NOT). However, this is not the case as the string is still printed despite the inclusion of the words I want to forbid.
Any advice on how to achieve this would be greatly appreciated, thanks in advance.
System.out.println("Type in an input, plez?");
String userInput6 = inputScanner.nextLine();
if (!userInput6.toLowerCase().contains("Java") || !userInput6.toLowerCase().contains("Code") || !userInput6.toLowerCase().contains("String")) {
System.out.println("I see your does not string contain 'Java', 'Code' or 'String, here is your string:- " + userInput6);
} else {
System.out.println("Your string contains 'Java, 'Code' or 'String'.");
}
I thought this would be achieved by using '!' (NOT)
It is. You just haven't applied it correctly to your situation:
You start with this statement:
userInput6.toLowerCase().contains("java") ||
userInput6.toLowerCase().contains("code") ||
userInput6.toLowerCase().contains("string")
which checks if the input contains any of these, and you wish to negate this statement.
You can either wrap the entire statement in parentheses (()) and negate that:
!(userInput6.toLowerCase().contains("java") ||
userInput6.toLowerCase().contains("code") ||
userInput6.toLowerCase().contains("string"))
or apply the DeMorgan's law for the negation of disjunctions which states that the negation of a || b is !a && !b.
So, as Carcigenicate stated in the comments, you would need
!userInput6.toLowerCase().contains("java") &&
!userInput6.toLowerCase().contains("code") &&
!userInput6.toLowerCase().contains("string")
instead.
Your statement is simply checking if the string doesn't contain at least one of these substrings. This means the check would only fail if the string contained all of these strings. With ||, if any operand is true, the entire statement is true.
Additionally, mkobit makes the point that your strings you are checking for should be entirely lowercase. Otherwise, you are checking if a .toLowerCased string contains an uppercase character - which is always false.
An easier way to think of it may be to invert your if statement:
if (userInput6.toLowerCase().contains("Java") ||
userInput6.toLowerCase().contains("Code") ||
userInput6.toLowerCase().contains("String")) {
System.out.println("Your string contains 'Java, 'Code' or 'String'.");
} else {
System.out.println("I see your does not string contain 'Java', 'Code' or 'String, here is your string:- " + userInput6);
}
Since you're using logical OR, as soon as one your contains checks it true, the entire condition is true. You want all the checks to be true, so you need to use logical AND (&&) instead
As #mk points out, you have another problem. Look at:
userInput6.toLowerCase().contains("Java")
You lower case the string, then check it against a string that contains an uppercase. You just removed all uppercase though, so that check will always fail.
Also, you can use regexp :)
boolean notContains(String in) {
return !Pattern.compile(".*((java)|(code)|(string)).*")
.matcher(in.toLowerCase())
.matches();
}
Or just inline it:
System.out.println("Type in an input, plez?");
String userInput6 = inputScanner.nextLine();
if (!Pattern.compile(".*((java)|(code)|(string)).*")
.matcher(userInput6.toLowerCase())
.matches()) {
System.out.println("I see your does not string contain 'Java', 'Code' or 'String, here is your string:- " + userInput6);
} else {
System.out.println("Your string contains 'Java, 'Code' or 'String'.");
}

Address with zip code. Java

The constructor will throw an IllegalArgumentException exception with the message "Invalid Address Argument" if any parameter is null, or if the zip code has characters others than digits.
The method Character.isDigit can help during the implementation of this method. See the Java API (Character class) for additional information.
I've had the illegal argument exception down. But, not the zip code. Help?
Program.
if(street==null||city==null||state==null){
throw new IllegalArgumentException("Invalid Address Argument");
}
if(zip == Character.isDigit(ch)){
//To do???
}
try apache stringutils
public static boolean isNumeric(CharSequence cs)
Checks if the CharSequence contains only Unicode digits. A decimal point is not a Unicode digit and returns false.
null will return false. An empty CharSequence (length()=0) will return false.
StringUtils.isNumeric(null) = false
StringUtils.isNumeric("") = false
StringUtils.isNumeric(" ") = false
StringUtils.isNumeric("123") = true
StringUtils.isNumeric("12 3") = false
StringUtils.isNumeric("ab2c") = false
StringUtils.isNumeric("12-3") = false
StringUtils.isNumeric("12.3") = false
Parameters:
cs - the CharSequence to check, may be null
Returns:
true if only contains digits, and is non-null
Since:
3.0 Changed signature from isNumeric(String) to isNumeric(CharSequence), 3.0 Changed "" to return false and not true
int zipcode = 0;
try {
zipcode = Integer.parseInt(zipcode);
}catch (Exception e){}
if (zipcode <= 0)
{
throw new Exception(..);
}
And less than 1,000,000 if you want to be precise. You are using Char which makes no sense as you will have a String.
This sounds like homework to me, so I think the first thing you need to do here is learn how to read the documentation. Let's start by taking your instructor's hint, and looking up the documentation for Character.isDigit(char ch)
public static boolean isDigit(char ch)
Handwaving away some of the terms there, the critical things are that the method is static (which means we call it like Character.isDigit(myVariable) and that it returns a boolean (true or false value), and that it accepts a parameter of type char.
So, to call this method, we need a char (single character). I'm assuming that your zip variable is a String. We know that a string is made up of multiple characters. So what we need is a way to get those characters, one at a time, from the String. You can find the documentation for the String class here.
There's a couple of ways to go about it. We could get the characters in an array using toCharArray(), or get a specific character out of the string using charAt(int index)
However you want to tackle it, you need to do this (in pseudocode)
for each char ch in zip
if ch is not a digit
throw new IllegalArgumentException("Invalid Address Argument")

Comparing String Integers Issue

I have a scanner that reads a 7 character alphanumeric code (inputted by the user). the String variable is called "code".
The last character of the code (7th character, 6th index) MUST BE NUMERIC, while the rest may be either numeric or alphabetical.
So, I sought ought to make a catch, which would stop the rest of the method from executing if the last character in the code was anything but a number (from 0 - 9).
However, my code does not work as expected, seeing as even if my code ends in an integer between 0 and 9, the if statement will be met, and print out "last character in code is non-numerical).
example code: 45m4av7
CharacterAtEnd prints out as the string character 7, as it should.
however my program still tells me my code ends non-numerically.
I'm aware that my number values are string characters, but it shouldnt matter, should it?
also I apparently cannot compare actual integer values with an "|", which is mainly why im using String.valueOf, and taking the string characters of 0-9.
String characterAtEnd = String.valueOf(code.charAt(code.length()-1));
System.out.println(characterAtEnd);
if(!characterAtEnd.equals(String.valueOf(0|1|2|3|4|5|6|7|8|9))){
System.out.println("INVALID CRC CODE: last character in code in non-numerical.");
System.exit(0);
I cannot for the life of me, figure out why my program is telling me my code (that has a 7 at the end) ends non-numerically. It should skip the if statement and continue on. right?
The String contains method will work here:
String digits = "0123456789";
digits.contains(characterAtEnd); // true if ends with digit, false otherwise
String.valueOf(0|1|2|3|4|5|6|7|8|9) is actually "15", which of course can never be equal to the last character. This should make sense, because 0|1|2|3|4|5|6|7|8|9 evaluates to 15 using integer math, which then gets converted to a String.
Alternatively, try this:
String code = "45m4av7";
char characterAtEnd = code.charAt(code.length() - 1);
System.out.println(characterAtEnd);
if(characterAtEnd < '0' || characterAtEnd > '9'){
System.out.println("INVALID CRC CODE: last character in code in non-numerical.");
System.exit(0);
}
You are doing bitwise operations here: if(!characterAtEnd.equals(String.valueOf(0|1|2|3|4|5|6|7|8|9)))
Check out the difference between | and ||
This bit of code should accomplish your task using regular expressions:
String code = "45m4av7";
if (!code.matches("^.+?\\d$")){
System.out.println("INVALID CRC CODE");
}
Also, for reference, this method sometimes comes in handy in similar situations:
/* returns true if someString actually ends with the specified suffix */
someString.endsWith(suffix);
As .endswith(suffix) does not take regular expressions, if you wanted to go through all possible lower-case alphabet values, you'd need to do something like this:
/* ASCII approach */
String s = "hello";
boolean endsInLetter = false;
for (int i = 97; i <= 122; i++) {
if (s.endsWith(String.valueOf(Character.toChars(i)))) {
endsInLetter = true;
}
}
System.out.println(endsInLetter);
/* String approach */
String alphabet = "abcdefghijklmnopqrstuvwxyz";
boolean endsInLetter2 = false;
for (int i = 0; i < alphabet.length(); i++) {
if (s.endsWith(String.valueOf(alphabet.charAt(i)))) {
endsInLetter2 = true;
}
}
System.out.println(endsInLetter2);
Note that neither of the aforementioned approaches are a good idea - they are clunky and rather inefficient.
Going off of the ASCII approach, you could even do something like this:
ASCII reference : http://www.asciitable.com/
int i = (int)code.charAt(code.length() - 1);
/* Corresponding ASCII values to digits */
if(i <= 57 && i >= 48){
System.out.println("Last char is a digit!");
}
If you want a one-liner, stick to regular expressions, for example:
System.out.println((!code.matches("^.+?\\d$")? "Invalid CRC Code" : "Valid CRC Code"));
I hope this helps!

Categories