HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Case insensitively removing a substring, efficiently

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
caseefficientlyremovingsubstringinsensitively

Problem

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 < s.length(); i++) {
        int j = s.indexOf(remove, i);

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

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

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

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

        if (j < 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 `

Solution

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.

Code Snippets

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

Context

StackExchange Code Review Q#86432, answer score: 4

Revisions (0)

No revisions yet.