How to let my code also check strings with length 0? - java

I am trying to remove the letter x if it is present as the first or last character of any given string. Why does my code not check strings with length 0 even though I have accounted for it in my code?
I have already tried using an if statement to check if the length is 0 and, if so, to return the original string. I have also tried returning an empty string with the same value.
public String withoutX(String str) {
if (((str.charAt(0)=='x') || str.charAt(str.length()-1) == 'x') && str.length()>=2){
if (str.charAt(0)=='x'){
str = str.substring(1,str.length());
} if (str.charAt(str.length()-1) == 'x'){
str = str.substring(0,str.length()-1);
}
} if (str.length()==1 && str == "x"){
return "";
} if (str.length()==0){
return str;
// the above if statement (length = 0) does not work
} else{
return str;
}
}
The expected result is for it to return the string without the letter x. This has been achieved for all strings, except an empty one, where it says that the index is out of range.

if (str.length() == 0) {
return str;
}
It should be at the top of the method body. Or, at least, it should go prior to getting str.charAt(0).
There's String#isEmpty.
The way you compared Strings is wrong. Use equals instead of ==.
Always validate the length before accessing a letter by index. Make sure that index in a string exists.

In this line:
if (((str.charAt(0)=='x') || str.charAt(str.length()-1) == 'x') && str.length()>=2)
you do check for the length of the string but after you check the indexes.
Change to:
if (str.length()>=2 && (str.charAt(0)=='x' || str.charAt(str.length()-1) == 'x'))
if str.length()>=2 is false the other conditions will not be checked because of Short Circuit Evaluation.
Also use equals() to compare strings and not ==.
I vwould write your method like this:
public String withoutX(String str) {
if (str.length() == 0 || (str.length() == 1 && str.equals("x")))
return "";
if (str.charAt(0) == 'x') {
str = str.substring(1, str.length());
}
if (str.charAt(str.length() - 1) == 'x') {
str = str.substring(0, str.length() - 1);
}
return str;
}
I kept your logic and removed unnecessary code.

I think this is a better implementation of what you are trying to do
public String withoutX(String str) {
if (str.startsWith("x")){
str = str.replaceFirst("x", "");
}
if (str.endsWith("x")){
str = str.substring(0,str.lastIndexOf("x"));
}
return str;
}

A simpler approach without making many corner-cases checking is to use regex to remove the leading and trail x - if it exists. Here's the code:
public String withoutX(String str){
return "".equals(str)? str: str.replaceAll("(^x|x$)", "");
}

Your code is checking for a x before you check if the string is empty. You should move
if (str.length()==0){
return str;
// the above if statement (length = 0) does not work
}
to the first line of the method. Besides that your code is great.

public String withoutX(String str) {
if (!str.isEmpty() && str.charAt(0)=='x'){
str = str.substring(1, str.length());
}
if (!str.isEmpty() && str.charAt(str.length()-1) == 'x'){
str = str.substring(0,str.length()-1);
}
return str;
}
You can first check, if the str is empty and remove the first x. Then check the size for greater than 1 and remove the last x. This leads to less and more readable code.

Related

Recursion string in JAVA

I'm writing with JAVA, and I wrote a recursive boolean function that gets 2 strings and is supposed to return if the first one is prefix of the second one.
My code:
public static boolean prefix(String s, String t)
{
int i = s.length()-1;
if (s.charAt(i) == t.charAt(i) && s.length() >= 0)
{
return true;
}
return false;
}
If I'm writing in the main for example:
s = "Del";
f = "Delight";
The function is working as well.
But if I'm writing s = "Dellll", f = "Dell", it says "Out of bounds". Why?
The second thing is that it's not working with big and small characters. For example:
s ="Dell"
f ="dell"
It will return true for the above.
Thank you.
What about using out-of-box solution?
public static boolean prefix(String str, String prefix) {
return str.startsWith(prefix);
}
In case you really need recursion:
public static boolean prefix(String str, String prefix) {
if (str == null || str.isEmpty())
return prefix == null || prefix.isEmpty();
if (prefix == null || prefix.isEmpty())
return true;
if (str.charAt(0) != prefix.charAt(0))
return false;
// remove first character of each string and go to next iteration
return prefix(str.substring(1), prefix.substring(1));
}
This is because you declare i as:
int i = s.length()-1;
And then call the ith char in both Strings
if (s.charAt(i) == t.charAt(i) && s.length() >= 0)
But if the first String is bigger than the second then i will be out of bounds. An easier way to do this would be to use the built in method startsWith, which:
Tests if this string starts with the specified prefix.
So your method could be as simple as:
return t.startsWith(s);
Or if you can't use built in methods, then you'll need to check if the first String is larger that the second:
if (s.charAt(i) == t.charAt(i) && s.length() >= 0 && s.length() < t.length())
Out of bounds means that, being the second string shorter than the first one, you are trying to access a character that doesn't exist. Just check the two lengths at the beginning of the function, and switch the parameters internally if needed.

Check a string for consonants

I want to write a method to check a string for consonants using either .contains or .indexOf.
I guess I could do it the long way and check for every consonant in the alphabet but I know there is a better way. This is what I have so far but like I said this is sort of the long way, I think.
public boolean containsConsonant(String searchString) {
if(searchString.contains("b") || searchString.contains("c")){
return true;
}
I think a simple for loop is most readable here, you can test that a character is within the desired range with a boolean and. And you can use an or test to skip vowels. Something like,
public boolean containsConsonant(String searchString) {
if (searchString == null) {
return false;
}
for (char ch : searchString.toCharArray()) {
char lower = Character.toLowerCase(ch);
if (lower >= 'a' && lower <= 'z') {
if (lower == 'a' || lower == 'e' || lower == 'i' ||
lower == 'o' || lower == 'u') continue;
return true;
}
}
return false;
}
Optimization
You could then optimize the above (and directly to your question) by using contains on an extracted constant String of vowels. Something like,
private static final String vowels = "aeiou";
public static boolean containsConsonant(final String searchString) {
if (searchString == null) {
return false;
}
for (char ch : searchString.toCharArray()) {
char lower = Character.toLowerCase(ch);
if (lower >= 'a' && lower <= 'z' && !vowels.contains(String.valueOf(lower))) {
return true;
}
}
return false;
}
I see that you explicitly ask using contains or indexOf
in case - if you can use matches - it would be very easy to implement.
public boolean containsConsonant(String searchString){
String consonants = ".*[bcdfghj].*"; //list the characters to be checked
return searchString.matches(consonants);
}
you can create say an array containing all consonants and then run it using a loop
e.g.
String[] consonants{"b", "c",....}
boolean containsConsonants(String searchString, String[]arr){
for (String consonant: arr){
if(searchString.contains(str)){ return true} return False

Java if-statement being skipped

The method below takes in a string and a pattern and returns true if they match each other. A '.' matches 1 char and a '*' matches 0 or more (e.g. expMatch("abc", "a.c") should return true). I added a bunch of print statements to see where I went wrong and it seems like the if statement is being skipped even if the str.length() == 1.
I call it with System.out.println(expMatch("abc", "a*c"));
Here is the code:
public static boolean expMatch(String str, String pat)
{
if (str.charAt(0) == pat.charAt(0) || pat.charAt(0) == '.')
{
System.out.println("in if");
System.out.println(str.charAt(0));
System.out.println(pat.charAt(0));
System.out.println(str.length());
if (str.length() == 1)
return true;
expMatch(str.substring(1), pat.substring(1));
}
else if (pat.charAt(0) == '*')
{
System.out.println("in else");
System.out.println(str.charAt(0));
System.out.println(pat.charAt(0));
if (str.length() == 1)
return true;
if (str.charAt(0) == pat.charAt(1)) //val of * = 0
expMatch(str, pat.substring(1));
else if (str.charAt(1) ==pat.charAt(1))
expMatch(str.substring(1), pat.substring(1));
}
return false;
}
and the output is:
in if
a
a
3
in else
b
*
in if
c
c
1
false
Even if the length is 1 it skips the if? Any idea why?
P.S. I'm not looking for the solution, just why the if statement is being skipped.
You always return false from the method at the very end. You are calling expmatch recursively but never using the return value. The code comes in to the first if, recurses (because length is not 1) and upon returning will go to the final return statement which returns false.
You need to add a return before your expMatch() calls - because the false comes from your last line return false;
What happens is this:
you call expMatch() with the two Strings.
you enter the if clause
the if clause enters expMatch() recursively
you enter the else clause
the else clause enters expMatch() recursively
you enter the if clause again
you leave the expMatch() method
you leave the other expMatch method
false is returned
Your approach is logically incorrect even if you apply the fixes the others suggested. Try this test case:
System.out.println(expMatch("abddddc", "a*c"));
This is because when you encounter a * in the pattern, you have no way to know how many characters "to eat" from the search string.
To say the least, you need a loop somewhere, not just an if. Let me try to fix it for you (not sure if it's possible though, not sure if you always know which path to take, I mean in your recursion). Think some more about it. Here is another unpleasant test case:
System.out.println(expMatch("adddcac", "a*c"));
// the * needs to eat dddca (despite the c present in dddca),
// it should not stop recursing there at that c
I think you need some sort of full search here.
Just an if or a while loop is not good enough.
EDIT: Here is a fixed version with a bunch of nasty tests. I think this is called non-linear recursion (as it's not a single path you try). Not 100% sure though about that term.
public class Test055 {
public static void main(String[] args) {
// System.out.println(expMatch("abddddc", "a*c"));
System.out.println(expMatch("adcax", "a*c"));
System.out.println(expMatch("adcax", "a*c*"));
System.out.println(expMatch("adcacm", "*"));
System.out.println(expMatch("adcacmmm", "a*c"));
System.out.println(expMatch("adcacmmmc", "a*c"));
System.out.println(expMatch("adcac", "a*c"));
System.out.println(expMatch("adcacxb", "a*c.b"));
System.out.println(expMatch("adcacyyb", "a*c.b"));
System.out.println(expMatch("adcacyyb", "a*c*b"));
}
public static boolean expMatch(String str, String pat)
{
// System.out.println("=====================");
// System.out.println("str=" + str);
// System.out.println("pat=" + pat);
if (pat.length() == 0 && str.length() > 0) {
return false;
} else if (pat.length() == 0 && str.length() == 0) {
return true;
} else if (pat.charAt(0) == '.'){
return str.length() >= 1 && expMatch(str.substring(1), pat.substring(1));
}else if (pat.charAt(0) != '*'){
return str.length() >= 1 && pat.charAt(0) == str.charAt(0) && expMatch(str.substring(1), pat.substring(1));
}else{
// Now let's handle the tricky part
// (1) Look for the 1st non-star in pattern
int k=-1;
char ch = ' ';
for (int i=0; i<pat.length(); i++){
if (pat.charAt(i) != '*'){
k = i;
ch = pat.charAt(k);
break;
}
}
if (k==-1){
// (2A) only stars found in pattern, OK, any str matches that
return true;
}else{
// (2B) do full search now checking all
// possible candidate chars in str that
// match the char ch from pattern
for (int i=0; i<str.length(); i++){
if (str.charAt(i)==ch){
boolean b = expMatch(str.substring(i+1), pat.substring(k+1));
if (b) return true;
}
}
return false;
}
}
}
}

Codingbat.com endX not resolving "other tests"

I'm working on a recursion problem from codingbat.com which states
Given a string, compute recursively a new string where all the lowercase 'x' chars have been moved to the end of the string.
It passes all of the examples except for the example that says "other tests." Since i can't see what "other tests" are referring to, I'm stuck. Any help would be appreciated. Here's my code
public String endX(String str) {
return endX2(str, 0, str.length());
}
public String endX2(String str, int n, int len){
if(len == 0) return str;
if(n == len-1) return str;
if(str.substring(n,n+1).equals("x")){
return str.substring(0,n) + (endX2(str.substring(n+1) + "x", n, len-1));
}
else return endX2(str, n+1, len);
}
I'm not sure why you have an additional method as it's unnecessary. You also have an additional check - if(n == len-1) return str; - that isn't needed.
The problem you're facing is the fact you're using unchecked indices and are getting lucky when the strings used do not end with an 'x' or a number of 'x's. If I use your code against String xs = "xfooxbarxx"; gets me a java.lang.StringIndexOutOfBoundsException. I haven't debugged the code extensively, but that should bring some understanding to the reason why it fails on the "other" tests. Take a look at my version and investigate for yourself where the issue may lie and how to perhaps make your code a bit more concise.
public String endX(String str) {
if(str.length() == 0)
return "";
return str.startsWith("x") ?
endX(str.substring(1)) + "x" :
String.valueOf(str.charAt(0)) + endX(str.substring(1));
}
PS: This is WAY WAY longer than it needs to be.
/*
Alright here is what we need to do...
Step 1: Get all the 'x' chars into a String.
Step 2: Get all NON 'x' chars into a String.
Step 3 (goal): Concencate (combine) the NON 'x' String first then the 'x' String in that order.
Solution Notes: Instead of using an index variable to go through a String, we could 'substring' off the first char in the String each time, cutting until we are down to the base case, for the sake of showing recursive logic I used an index varible. However on Arrays or any other collection, you need an index varible to access that element ant that spot or (index).
*/
public String endX(String str) {
//Ternary operator used here...could be written as a full if then else statement.
//Ternary operator logic: if the length is 0 return "", else return getNonX(str, "", 0) + getX(str, "", 0);
return (str.length() == 0) ? "" : getNonX(str, "", 0) + getX(str, "", 0);
//NOTICE in the parts [getNonX(str, "", 0)] and [getX(str, "", 0)]
//there is an empty String in the middle, that is there to hold or gather the
//chars, 'x' or not. We fill those empty Strings up in each recursive helper
}
public String getX(String str, String x, int index) {
//We are at the end, and if the last char IS an 'x'...
if(index == str.length() - 1 && str.charAt(index) == 'x'){
return x + 'x'; //...put that last 'x' on the 'x' String.
}
//We are at the end and if the last char IS NOT an 'x'...
else if(index == str.length() - 1 && str.charAt(index) != 'x'){
return x; //...just return what we got.
}
//When we see an 'x' but we aren't at the end...
if(index < str.length() - 1 && str.charAt(index) == 'x'){
x += 'x'; //...append 'x' to the 'x' String.
}
return getX(str, x, index + 1); //recur, moving the index up
}
public String getNonX(String str, String nonX, int index) {
//We are at the end, and if the last char IS NOT an 'x'...
if(index == str.length() - 1 && str.charAt(index) != 'x'){
return (nonX + str.charAt(index)); //...append that char to the 'nonX' String
}
//We are at the end and if the last char IS an 'x'...
else if(index == str.length() - 1 && str.charAt(index) == 'x'){
return nonX; //...just return what we got.
}
//When we see a non 'x' char and we aren't at the end...
if(index < str.length() - 1 && str.charAt(index) != 'x'){
nonX += str.charAt(index); //...append that char to the 'nonX' String
}
return getNonX(str, nonX, index + 1); //recur, move the index up
}
You can try this code...
public String endX(String str) {
if(str.length() <=1) return str;
if(str.charAt(0) == 'x') return endX(str.substring(1)) + 'x';
return str.charAt(0) + endX(str.substring(1));
}

Writing a method to remove vowels in a Java String [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am a beginner of programming, and am writing a Java method to remove vowel in Strings, but I do not know how to fix this error: ";" expected :
public String disemvowel(String s) {
boolean isVowel(char c);
if (c == 'a') {
return true;
} else if if (c == 'e') {
return true;
} else if if (c == 'i') {
return true;
} else if if (c == 'o') {
return true;
} else if if (c == 'u') {
return true;
}
String notVowel = "";
int l = s.length();
for (int z = 0; z <= l; z++) {
if (isVowel == "false") {
char x = s.charAt(z);
notVowel = notVowel + x;
}
}
return notVowel;
}
String str= "Your String";
str= str.replaceAll("[AEIOUaeiou]", "");
System.out.println(str);
A much simpler approach would be to do the following:
String string = "A really COOL string";
string = string.replaceAll("[AaEeIiOoUu]", "");
System.out.println(string);
This will apply the regular expression, [AaEeIiOoUu] to string. This expression will match all vowels in the character group [AaEeIiOoUu] and replace them with "" empty string.
You've got a lot of syntax errors.
boolean isVowel(char c); - not sure what you're doing with this. if you want it as a separate method, separate it out (and don't place a semicolon after it, which would be invalid syntax.
else if if is invalid syntax. If you're doing an else if, then you only need the one if.
Even if the code would compile, for (int z = 0; z <= l; z++) will cause you to step off of the String. Remove the <= in favor of <.
isVowel == "false" is never going to work. You're comparing a String to a boolean. You want !isVowel instead.
Putting the syntax errors aside, think of it like this.
You have a string that contains vowels. You wish to have a string that doesn't contain vowels.
The most straightforward approach is to iterate over the String, placing all non-vowel characters into a separate String, which you then return.
Interestingly enough, the half-method you have there can accomplish the logic of determining whether something is or isn't a vowel. Extract that to its own method. Then, call it in your other method. Do take into account capital letters though.
I leave the rest as an exercise to the reader.
Here is your code, without changing any logic, but unscrambling the isVowel method:
public String disemvowel(String s) {
// Removed the "isVowel" method from here and moved it below
String notVowel = "";
int l = s.length();
for (int z = 0; z <= l; z++) {
// Note that the "isVowel" method has not been called.
// And note that, when called, isVowel returns a boolean, not a String.
// (And note that, as a general rule, you should not compare strings with "==".)
// So this area needs a lot of work, but we'll start with this
boolean itIsAVowel = isVowel(s.charAt(z));
// (I made the variable name "itIsAVowel" to emphasize that it's name has nothing to do with the method name.
// You can make it "isVowel" -- the same as the method -- but that does not in any way change the function.)
// Now take it from there...
if (isVowel == "false") {
char x = s.charAt(z);
notVowel = notVowel + x;
}
}
return notVowel;
}
// You had this line ending with ";"
boolean isVowel(char c) {
if (c == 'a') {
return true;
// Note that you coded "if if" on the lines below -- there should be only one "if" per line, not two
} else if if (c == 'e') {
return true;
} else if if (c == 'i') {
return true;
} else if if (c == 'o') {
return true;
} else if if (c == 'u') {
return true;
}
// You were missing this final return
return false;
}
(Yes, I know this should be a comment, but you can't put formatted code in a comment.)
You could try something like this:
public static String removeVowels(final String string){
final String vowels = "AaEeIiOoUu";
final StringBuilder builder = new StringBuilder();
for(final char c : string.toCharArray())
if(vowels.indexOf(c) < 0)
builder.append(c);
return builder.toString();
}

Categories

Resources