Replace all occurrences of a String using StringBuilder?

Java

Java Problem Overview


Am I missing something, or does StringBuilder lack the same "replace all occurrences of a string A with string B" function that the normal String class does? The StringBuilder replace function isn't quite the same. Is there any way to this more efficiently without generating multiple Strings using the normal String class?

Java Solutions


Solution 1 - Java

Well, you can write a loop:

public static void replaceAll(StringBuilder builder, String from, String to) {
    int index = builder.indexOf(from);
    while (index != -1) {
        builder.replace(index, index + from.length(), to);
        index += to.length(); // Move to the end of the replacement
        index = builder.indexOf(from, index);
    }
}

Note that in some cases it may be faster to use lastIndexOf, working from the back. I suspect that's the case if you're replacing a long string with a short one - so when you get to the start, any replacements have less to copy. Anyway, this should give you a starting point.

Solution 2 - Java

You could use Pattern/Matcher. From the Matcher javadocs:

 Pattern p = Pattern.compile("cat");
 Matcher m = p.matcher("one cat two cats in the yard");
 StringBuffer sb = new StringBuffer();
 while (m.find()) {
     m.appendReplacement(sb, "dog");
 }
 m.appendTail(sb);
 System.out.println(sb.toString());

Solution 3 - Java

@Adam: I think in your code snippet you should track the start position for m.find() because string replacement may change the offset after the last character matched.

public static void replaceAll(StringBuilder sb, Pattern pattern, String replacement) {
    Matcher m = pattern.matcher(sb);
    int start = 0;
    while (m.find(start)) {
        sb.replace(m.start(), m.end(), replacement);
        start = m.start() + replacement.length();
    }
}

Solution 4 - Java

Look at JavaDoc of replaceAll method of String class:

> Replaces each substring of this string that matches the given regular > expression with the given replacement. An invocation of this method > of the form str.replaceAll(regex, repl) yields exactly the same result > as the expression > > java.util.regex.Pattern.compile(regex).matcher(str).replaceAll(repl)

As you can see you can use Pattern and Matcher to do that.

Solution 5 - Java

The class org.apache.commons.lang3.text.StrBuilder in Apache Commons Lang allows replacements:

public StrBuilder replaceAll(String searchStr, String replaceStr)

* This does not receive a regular expression but a simple string.

Solution 6 - Java

Even simple one is using the String ReplaceAll function itself. You can write it as

StringBuilder sb = new StringBuilder("Hi there, are you there?")
System.out.println(Pattern.compile("there").matcher(sb).replaceAll("niru"));

Solution 7 - Java

Yes. It is very simple to use String.replaceAll() method:

package com.test;

public class Replace {

	public static void main(String[] args) {
		String input = "Hello World";
		input = input.replaceAll("o", "0");
		System.out.println(input);
	}
}

Output:

Hell0 W0rld

If you really want to use StringBuilder.replace(int start, int end, String str) instead then here you go:

public static void main(String args[]) {
    StringBuilder sb = new StringBuilder("This is a new StringBuilder");

    System.out.println("Before: " + sb);

    String from = "new";
    String to = "replaced";
    sb = sb.replace(sb.indexOf(from), sb.indexOf(from) + from.length(), to);

    System.out.println("After: " + sb);
}

Output:

Before: This is a new StringBuilder
After: This is a replaced StringBuilder

Solution 8 - Java

java.util.regex.Pattern.matcher(CharSequence s) can use a StringBuilder as an argument so you can find and replace each occurence of your pattern using start() and end() without calling builder.toString()

Solution 9 - Java

Use the following:

/**
* Utility method to replace the string from StringBuilder.
* @param sb	         the StringBuilder object.
* @param toReplace	 the String that should be replaced.
* @param replacement the String that has to be replaced by.
* 
*/
public static void replaceString(StringBuilder sb,
                                 String toReplace,
                                 String replacement) {		
    int index = -1;
    while ((index = sb.lastIndexOf(toReplace)) != -1) {
        sb.replace(index, index + toReplace.length(), replacement);
    }
}

Solution 10 - Java

Here is an in place replaceAll that will modify the passed in StringBuilder. I thought that I would post this as I was looking to do replaceAll with out creating a new String.

public static void replaceAll(StringBuilder sb, Pattern pattern, String replacement) {
	Matcher m = pattern.matcher(sb);
	while(m.find()) {
		sb.replace(m.start(), m.end(), replacement);
	}
}

I was shocked how simple the code to do this was (for some reason I thought changing the StringBuilder while using the matcher would throw of the group start/end but it does not).

This is probably faster than the other regex answers because the pattern is already compiled and your not creating a new String but I didn't do any benchmarking.

Solution 11 - Java

public static String replaceCharsNew(String replaceStr,Map<String,String> replaceStrMap){
		StringBuilder replaceStrBuilder = new StringBuilder(replaceStr);
		Set<String> keys=replaceStrMap.keySet();
		for(String invalidChar:keys){
		    int index = -1;
			while((index=replaceStrBuilder.indexOf(invalidChar,index)) !=-1){
				replaceStrBuilder.replace(index,index+invalidChar.length(),replaceStrMap.get(invalidChar));
			}
		}
		return replaceStrBuilder.toString();
	}

Solution 12 - Java

How about create a method and let String.replaceAll do it for you:

public static void replaceAll(StringBuilder sb, String regex, String replacement)
{
	String aux = sb.toString();
	aux = aux.replaceAll(regex, replacement);
	sb.setLength(0);
	sb.append(aux);		
}

Solution 13 - Java

I found this method: Matcher.replaceAll(String replacement); In java.util.regex.Matcher.java you can see more:

 /**
 * Replaces every subsequence of the input sequence that matches the
 * pattern with the given replacement string.
 *
 * <p> This method first resets this matcher.  It then scans the input
 * sequence looking for matches of the pattern.  Characters that are not
 * part of any match are appended directly to the result string; each match
 * is replaced in the result by the replacement string.  The replacement
 * string may contain references to captured subsequences as in the {@link
 * #appendReplacement appendReplacement} method.
 *
 * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
 * the replacement string may cause the results to be different than if it
 * were being treated as a literal replacement string. Dollar signs may be
 * treated as references to captured subsequences as described above, and
 * backslashes are used to escape literal characters in the replacement
 * string.
 *
 * <p> Given the regular expression <tt>a*b</tt>, the input
 * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
 * <tt>"-"</tt>, an invocation of this method on a matcher for that
 * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
 *
 * <p> Invoking this method changes this matcher's state.  If the matcher
 * is to be used in further matching operations then it should first be
 * reset.  </p>
 *
 * @param  replacement
 *         The replacement string
 *
 * @return  The string constructed by replacing each matching subsequence
 *          by the replacement string, substituting captured subsequences
 *          as needed
 */
public String replaceAll(String replacement) {
    reset();
    StringBuffer buffer = new StringBuffer(input.length());
    while (find()) {
        appendReplacement(buffer, replacement);
    }
    return appendTail(buffer).toString();
}

Solution 14 - Java

Kotlin Method

  fun replaceAllStringBuilder(
        builder: java.lang.StringBuilder,
        from: String,
        to: String
    ) {
        if (!builder.contains(from)||from.isNullOrEmpty()) return
        
            var index = builder.indexOf(from)
            while (index != -1) {
                builder.replace(index, index + from.length, to)
                index += to.length 
                index = builder.indexOf(from, index)
            }
        

    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmeteoritepanamaView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaRon RomeroView Answer on Stackoverflow
Solution 3 - Javafir99View Answer on Stackoverflow
Solution 4 - JavaAlfredo OsorioView Answer on Stackoverflow
Solution 5 - JavaPaul VargasView Answer on Stackoverflow
Solution 6 - Javauser2995215View Answer on Stackoverflow
Solution 7 - JavaAmitabha RoyView Answer on Stackoverflow
Solution 8 - JavaPierreView Answer on Stackoverflow
Solution 9 - JavaAnandanView Answer on Stackoverflow
Solution 10 - JavaAdam GentView Answer on Stackoverflow
Solution 11 - JavarameshView Answer on Stackoverflow
Solution 12 - JavaChristianView Answer on Stackoverflow
Solution 13 - JavaCodiosView Answer on Stackoverflow
Solution 14 - JavaMayank SharmaView Answer on Stackoverflow