Case insensitively removing a substring, efficiently I am going through the CodingBat exercises for Java. I have just completed this one:


  Given two strings, base and remove, return a version of the base string where all instances of the remove string have been removed (not case sensitive). You may assume that the remove string is length 1 or more. Remove only non-overlapping instances, so with xxx removing xx leaves x. 


I wanted to try using a StringBuilder to solve this because I have not done so before. Here is my code:

public String withoutString(String base, String remove){

    String removeLo = remove.toLowerCase();
    String removeHi = remove.toUpperCase();

    int rL = remove.length();

    StringBuilder s = new StringBuilder(base);

    for (int i = 0; i &lt; s.length(); i++) {
        int j = s.indexOf(remove, i);

        if (j &lt; 0) {
            break;
        } else {
            s.delete(j, j + rL);
        }
    }

    for (int i = 0; i &lt; s.length(); i++) {
        int j = s.indexOf(removeLo, i);

        if (j &lt; 0) {
            break;
        } else {
            s.delete(j, j + rL);
        }
    }

    for (int i = 0; i &lt; s.length(); i++) {
        int j = s.indexOf(removeHi, i);

        if (j &lt; 0) {
            break;
        } else {
            s.delete(j, j + rL);
        }
    }   
    return s.toString();
}


The code repeats the for loop 3 times in order to search for the unaltered, lower case, and upper case versions of remove. My questions are:


Is it possible to reduce this down to one for loop, and is that practical (with good readability)?
The test strings involve digits. Is it problematic to be 'converting' these to lower and/or upper cases? Should I deal with those before testing the alphabetic strings?
The following test cases are the ones that require all three for loops:

withoutString("xxx", "x")
withoutString("1111", "1")
withoutString("MkjtMkx", "Mk")
withoutString("Hi HoHo", "Ho")


The rest of the tests work without the first for loop (unaltered remove). The second two make sense, because the remove string uses upper and lower case, but the first two don't follow this. I have used the debugger in Eclipse but I still can't figure this out. Can you please explain?
Regular expressions make your life really easy when solving such exercises:

public static String withoutString(String base, String remove) {
    return Pattern.compile(Pattern.quote(remove), Pattern.CASE_INSENSITIVE).matcher(base).replaceAll("");
}


I explain this code a little:


Pattern.compile(Pattern.quote(remove), Pattern.CASE_INSENSITIVE): Creates a regular expression pattern containing the string you want to have removed. Pattern.quote(remove) takes care of special characters that may be interpreted as a regular expression (such as: *, \, +, (), [] etc.). The flag Pattern.CASE_INSENSITIVE makes sure, that the case of the characters don't matter.
.matcher(base): returns a Matcher that holds all matches of the regular expression in the string base.
.replaceAll("");: replaces all matches that have been found with an empty string, effectively removing them.


You may have noticed, that I made this method static because it does not access any fields or methods that are non-static. This is always advised unless it really needs to be non-static for some reason.