1. Overview
In this tutorial, we’re going to be looking at various means we can remove or replace part of a String in Java.
We’ll explore removing and/or replacing a substring using a String API, then using a StringBuilder API and finally using the StringUtils class of Apache Commons library.
As a bonus, we’ll also look into some common String replacement problems, such as replacing an exact word and removing all characters until a specific one.
2. String API
One of the simplest and straightforward methods of replacing a substring is using the replace, replaceAll or replaceFirst of a String class.
The replace() method takes two arguments – target and replacement text:
String master = "Hello World Baeldung!";
String target = "Baeldung";
String replacement = "Java";
String processed = master.replace(target, replacement);
assertTrue(processed.contains(replacement));
assertFalse(processed.contains(target));
The above snippet will yield this output:
Hello World Java!
If a regular expression is required in choosing the target, then the replaceAll() or replaceFirst() should be the method of choice. As their name implies, replaceAll() will replace every matched occurrence, while the replaceFirst() will replace the first matched occurrence:
String master2 = "Welcome to Baeldung, Hello World Baeldung";
String regexTarget = "(Baeldung)$";
String processed2 = master2.replaceAll(regexTarget, replacement);
assertTrue(processed2.endsWith("Java"));
The value of processed2 will be:
Welcome to Baeldung, Hello World Java
It’s because the regex supplied as regexTarget will only match the last occurrence of Baeldung. In all examples given above, we can use an empty replacement and it’ll effectively remove a target from a master.
3. StringBuilder API
We can also manipulate text in Java using the StringBuilder class*.* The two methods here are delete() and replace().
We can construct an instance of a StringBuilder from an existing String and then use the methods mentioned to perform the String manipulation as desired:
String master = "Hello World Baeldung!";
String target = "Baeldung";
String replacement = "Java";
int startIndex = master.indexOf(target);
int stopIndex = startIndex + target.length();
StringBuilder builder = new StringBuilder(master);
Now we can remove the target with the delete():
builder.delete(startIndex, stopIndex);
assertFalse(builder.toString().contains(target));
We can as well use the replace() to update the master:
builder.replace(startIndex, stopIndex, replacement);
assertTrue(builder.toString().contains(replacement));
One apparent difference between using the StringBuilder and the String API is that we’ve to get the start and the stop index of the target String ourselves.
4. StringUtils Class
Another method we’ll consider is the Apache Commons library.
First, let’s add the required dependency to our project:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>
The latest version of the library can be found here.
The StringUtils class has methods for replacing a substring of a String:
String master = "Hello World Baeldung!";
String target = "Baeldung";
String replacement = "Java";
String processed = StringUtils.replace(master, target, replacement);
assertTrue(processed.contains(replacement));
There is an overloaded variant of the replace() that takes an integer max parameter, which determines the number of occurrences to replace. We can also use the replaceIgnoreCase() if case-sensitivity is not a concern:
String master2 = "Hello World Baeldung!";
String target2 = "baeldung";
String processed2 = StringUtils.replaceIgnoreCase(master2, target2, replacement);
assertFalse(processed2.contains(target));
Next, let’s look at some common String replacement problems.
5. Replacing Exact Words
In this example, we’ll learn how to replace an exact word inside a String.
The straightforward way to perform this replacement is using a regular expression with word boundaries.
The word boundary regular expression is \b. Enclosing the desired word inside this regular expression will only match exact occurrences.
First, let’s see how to use this regular expression with the String API:
String sentence = "A car is not the same as a carriage, and some planes can carry cars inside them!";
String regexTarget = "\\bcar\\b";
String exactWordReplaced = sentence.replaceAll(regexTarget, "truck");
The exactWordReplaced string contains:
"A truck is not the same as a carriage, and some planes can carry cars inside them!"
Only the exact word will be replaced. Notice backward slash always needs to be escaped when working with regular expressions in Java.
An alternate way to do this replacement is using the RegExUtils class from the Apache Commons Library, which can be added as a dependency as we saw in the previous section:
String regexTarget = "\\bcar\\b";
String exactWordReplaced = RegExUtils.replaceAll(sentence, regexTarget, "truck");
While both methods will yield the same result, deciding which one should be used will depend on our specific scenario.
6. Removing All Characters Until a Specific One
In real-world projects, we sometimes need to remove all characters until a specific character from a String input. An example can quickly explain the problem:
static final String INPUT1 = "some prefix=Important Info: a=b";
Let’s assume we have the above String input, and *our task is to remove everything until the first equal (‘=‘) character.* Therefore, our expected result is “Important Info: a=b”.
This is an “inclusive” scenario, as we remove the characters including the first equal character. Additionally, there is an “exclusive” scenario. Next, let’s see another example:
static final String INPUT2 = "some prefix<a, <b, c>>"
Given INPUT2, we aim to remove everything until the first ‘<*‘ character exclusively**. That is to say, **we expect to see *“<a, <b, c>>” as a result.**
Next, let’s solve the problem using different methods. Of course, we’ll discuss both inclusive and exclusive scenarios.
For simplicity, we’ll skip the input validation part and assume the input always contain at least one ‘=’ character.
6.1. Using indexOf() and substring()
The String.indexOf() method finds the first occurrence index of a String in another String. Also, the String.substring() method allows us to extract a substring from the input String by providing a beginIndex (inclusive) and optionally an endIndex (exclusive).
Next, let’s combine these to standard methods to solve the problem:
String result1 = INPUT1.substring(INPUT1.indexOf("=") + 1);
assertEquals("Important Info: a=b", result1);
As the code above shows, we initially used indexOf() to retrieve the index of the first ‘=‘ character in the input. *Since we aim to remove the first ‘=‘ character as well, we applied “+ 1*” to the index we obtained.
Subsequently, we passed this calculated index to substring() as the beginIndex argument. It’s worth noting that as we didn’t specify the endIndex argument, substring() returns characters from beginIndex to the end of the input.
It’s not a challenge to adjust the solution to make it work for the “exclusive” scenario. *If we want to exclude the target character, we just don’t apply “ + 1” to the indexOf() result:*
String result2 = INPUT2.substring(INPUT2.indexOf("<"));
assertEquals("<a, <b, c>>", result2);
6.2. Using split()
Our input can be considered as two parts separated by an ‘*=*‘ character:
INPUT : "some prefix=Important Info: a=b"
Part1 : "some prefix"
Separator : '='
Part2 : Important Info: a=b"
Another idea to solve the problem is for us to split the input into two parts and take only the second part.
The split() method allows us to split an input String into multiple String values by providing a regex-based separator. Additionally, we can provide the limit argument to specify the desired number of elements in the resulting array. Since we aim to split the input into two parts, let’s pass 2 as the limit to split():
String result1 = INPUT1.split("=", 2)[1];
assertEquals("Important Info: a=b", result1);
If we intend to use split() to address the “exclusive” scenario, we must provide split() a zero-width assertion regex, such as a positive lookahead assertion:
String result2 = INPUT2.split("(?=<)", 2)[1];
assertEquals("<a, <b, c>>", result2);
The “(?=<)” pattern asserts that the current position in the input String is followed by the character ‘*<*‘. However, it doesn’t include ‘*<*‘ in the overall match.
6.3. Using replaceFirst()
We’ve previously witnessed the effectiveness of regex-based replacement. This problem isn’t a challenge for regex-based replacement either.
We can use replaceFirst() to solve this problem. replaceFirst() works pretty similar to replaceAll(). The difference is, as its name tells, replaceFirst() applies the substitution on the match only once.
Some might consider using replaceFirst() with the regex pattern “*.**=”. Let’s see if this approach helps us achieve the desired outcome:
String wrongResult = INPUT.replaceFirst(".*=", "");
assertEquals("b", wrongResult);
As the test above shows, after the replacement, we got “b” as the result. This is because ‘***‘ is a greedy quantifier. Thus, *“.*=” matches anything up until the last ‘=‘ character in the input.* This greedy matching is also a common pitfall.
There are several ways to address the “greedy matching” issue. One approach is to append a question mark after “*.**“, to turn it into a non-greedy pattern:
String result1 = INPUT1.replaceFirst(".*?=", "");
assertEquals("Important Info: a=b", result1);
As a non-greedy pattern, “*.*?=*” matches anything until the first equal character.
Alternatively, we can *use the negate operator (^) within a character class ([^=]) to match any character other than ‘=‘*:
result1 = INPUT1.replaceFirst("[^=]*=", "");
assertEquals("Important Info: a=b", result1);
Finally, let’s slightly adjust this solution to address the “exclusive” scenario:
String result2 = INPUT2.replaceFirst("[^<]*", "");
assertEquals("<a, <b, c>>", result2);
As demonstrated, by excluding the target character from the pattern, we successfully solved the problem.
7. Replacing the Last Occurrence of a Text
Sometimes, the input can contain the same text multiple times, but we only want to replace the last occurrence. Let’s say we have this String:
final static String INPUT3 = "The first word, the second word, the last word should be replaced.";
Now, we want to replace the last “word” with “**WORD**” to have the following result:
final static String EXPECTED3 = "The first word, the second word, the last *WORD* should be replaced.";
In this section, let’s explore two different ways to achieve this.
7.1. Reversing, Replacing, and Reversing Again
We’ve learned replaceFirst() replaces the first occurrence with a desired replacement. However, we aim to replace the last occurrence of the target pattern. Therefore, if we can somehow transform the last occurrence into the first occurrence, then we can use the replaceFirst() method to solve the problem.
Following this idea, we can reverse the input String to turn the last occurrence into the first one:
".decalper eb dluohs drow tsal eht ,drow dnoces eht ,drow tsrif ehT"
However, as we can see, after reversing the input, the target text gets reversed: “word” becomes “drow”
Therefore, we must reverse the target text and the replacement to call replaceFirst(). Of course, *after calling replaceFirst(), we shouldn’t forget to reverse the result to get the expected result.*
There are many ways to reverse a String in Java. Let’s create a method to use StringBuilder to perform the reverse operation:
String reverseString(String input) {
return new StringBuilder(input).reverse().toString();
}
Next, let’s implement the logic we discussed earlier:
String theWord = "word";
String replacement = "*WORD*";
String reversedInput = reverseString(INPUT3);
String reversedTheWord = reverseString(theWord);
String reversedReplacement = reverseString(replacement);
String reversedResult = reversedInput.replaceFirst(reversedTheWord, reversedReplacement);
String result = reverseString(reversedResult);
assertEquals(EXPECTED3, result);
As the test above shows, this approach does the job.
7.2. Using the lastIndexOf() Method
The “reverse-replace-reverse” approach solves the problem. However, we have to reverse everything, such as the input, the target text, the replacement, and the result.
Alternatively, we can achieve our goal in a more straightforward way using the lastIndexOf() method from the standard library:
String theWord = "word";
String replacement = "*WORD*";
int index = INPUT3.lastIndexOf(theWord);
String result = INPUT3.substring(0, index) + replacement + INPUT3.substring(index + theWord.length());
assertEquals(EXPECTED3, result);
Finally, let’s walk through the code to understand how it works.
First, we find the last occurrence using lastIndexOf() to locate the position of the last occurrence of the target word. Then, we divide and concatenate, dividing the input into two parts (before and after the last occurrence), and then concatenating them with the replacement: before + replacement + after.
8. Conclusion
In conclusion, we’ve explored multiple ways of removing and replacing a substring in Java. The best method to apply still largely depends on the current situation and context.
As usual, the complete source code is available over on GitHub.