简体   繁体   中英

Remove a Character From String in Java

I'm trying to concatenate a string with itself and remove all capital letters from the resultant string.

Here is my code:

public String removeCapitals(String A) {
    StringBuilder B = new StringBuilder(A+A);
    int n = B.length();

    for(int i=0; i<n; i++){
        if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
            B.deleteCharAt(i);
        }
    }

    return B.toString();
}

I'm getting Exception saying:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 6
at java.lang.AbstractStringBuilder.charAt(AbstractStringBuilder.java:237)
at java.lang.StringBuilder.charAt(StringBuilder.java:76)
at Solution.removeCapitals(Solution.java:10)
at Main.main(Main.java:190)

Can someone help me to understand the issue.

If at least one removal succeeds, at some point your code will attempt to access an invalid index that exceeds the length of a StringBuilder .

It happens because the variable n remain unchanged. You should change the condition to be bound to the current size of StringBuilder and decrement the index at each removal, or iterate backwards (as shown in another answer).

Also condition B.charAt(i)>='A' && B.charAt(i)<='Z' can be replaced with:

Character.isUpperCase(b.charAt(i))

Which is more descriptive.

That's how it might look like:

 public static String removeCapitals(String a) {
    
    StringBuilder b = new StringBuilder(a + a);
    
    for (int i = 0; i < b.length(); i++) {
        if (Character.isUpperCase(b.charAt(i))) {
            b.deleteCharAt(i); // which can be combined with the next line `b.deleteCharAt(i--);` - previous value of `i` would be used in the call `deleteCharAt()` and variable `i` will hold a value decremented by 1
            i--;
        }
    }
    return b.toString();
}

Method deleteCharAt() runs in a linear time, because it shifts all subsequent characters in the underlying array bytes. Each upper-case letter will trigger these shifts and in the worst case scenario, it would result in the quadratic overall time complexity O(n ^ 2) .

You make your method more performant and much more concise without using loops and StringBuilder . This code will run in a linear time O(n) .

public static String removeCapitals(String a) {
    
    return a.replaceAll("\\p{Upper}", "").repeat(2);
}

When you delete a character you change the length of the StringBuilder. But n still has the original length. So you will eventually exceed the size of the StringBuilder . So start from the end and move backwards. That way, any deletions will come after (based on relative indices) the next position so the index will be within the modified StringBuilder size. In addition, deleting from the end is more efficient since there is less copying to do in the StringBuilder.

public String removeCapitals(String A) {
    StringBuilder B = new StringBuilder(A+A);
    int n = B.length(); 

    for(int i=n-1; i>=0; i--){
        if(B.charAt(i)>='A' && B.charAt(i)<='Z'){
            B.deleteCharAt(i);
        }
    }

    return B.toString();
}

If just remove Capital characters from a string. Alternative solution just create another method replaceAll() + regex

private static String removeCapitals(String A){
    if (!A.isEmpty() && !A.equals("")) {
        String B = A + A;
        String newStr = B.replaceAll("([A-Z])", "");
        return newStr;
    } else {
        return null;
    }
}

Shorter solution to your task.

String a = "ABcdEF";
String b = "";
for (int i = 0; i < a.length(); i++) {
    if(a.toLowerCase().charAt(i) == a.charAt(i))
       b+=a.charAt(i);
    }
    System.out.println(b);

By changing to .toUpperCase() you'll get rid of the lower case ones.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM