Redacting everything in a string except a particular word I am working through the Coding Bat exercises for Java. Here is one I have just completed:


  Given a string and a non-empty word string, return a version of the original String where all chars have been replaced by pluses ("+"), except for appearances of the word string which are preserved unchanged.


And here is my solution:

public String plusOut(String str, String word){

    String s = "";
    String n = str + "  ";

    int i = 0;
    while(i &lt; str.length()) {

        if (!(n.substring(i, i + word.length()).equals(word))) {
            s += "+";
            i++;
        } else {
            s += word;
            i += word.length();
        }
    }

    return s;
}


As you can see, I concatenated two spaces on the original string and used that to test the substrings. This was to avoid out of bounds exceptions.

What I want to do is optimise my solution, because I don't like how I added two spaces just to avoid errors. I want to change the if statement so that it tests the substrings of str rather than n, and get rid of n entirely. I have tried but I can't seem to find a way of doing it. How can I do this? What else needs optimising?
Manipulating Strings directly is a bad idea, especially when you are doing it repeatedly.  Java strings are immutable, so every time you do s += …, you are making a copy of the entire provisional result.  Anytime you need to do a substantial amount of editing on a string, use a StringBuilder.

To look for the next occurrence of word, use String.indexOf() or StringBuilder.indexOf().  It's a lot easier than extracting substrings and checking for equality.  When extracting the substring, your code crashes if word is longer than three characters.  Using .indexOf() is one way to eliminate that problem.

Here is an example of a more efficient solution:

public String plusOut(String str, String word) {
    StringBuilder s = new StringBuilder(str);

    // Find substrings to redact, from index i (inclusive)
    // to index j (exclusive)
    for (int i = 0; i &lt; s.length(); i += word.length()) {
        int j = s.indexOf(word, i);
        if (j &lt; 0) {
            // word not found; redact the rest of the string
            j = s.length();
        }

        while (i &lt; j) {
            s.setCharAt(i++, '+');
        }
    }
    return s.toString();
}