Explain Codes LogoExplain Codes Logo

How to replace case-insensitive literal substrings in Java

java
regex
performance
best-practices
Alex KataevbyAlex Kataev·Dec 10, 2024
TLDR

To perform a case-insensitive substring replacement in Java, use Pattern with Pattern.CASE_INSENSITIVE and Matcher's replaceAll():

String result = Pattern.compile(Pattern.quote("example"), Pattern.CASE_INSENSITIVE) .matcher("Example string with ExAmple.") .replaceAll(Matcher.quoteReplacement("sample")); // The "Example" and "ExAmple" have now seen the light and turned into "sample".

This approach creates a pattern for the target string with Pattern.quote to prevent regex syntax from interfering with the literal text. Mark the insensitivity flag and perform a literal replacement on all matches in the input string. It's a one-liner for efficiency!

Dancing with special characters

If the replacement string has some special characters, softball them with Matcher.quoteReplacement:

String replacement = Matcher.quoteReplacement("$sample$"); String result = Pattern.compile(Pattern.quote("example"), Pattern.CASE_INSENSITIVE) .matcher("Example string.") .replaceAll(replacement); // "$ample$" enters the chat, no special attention needed.

Looping like a pro

Doing replacements in a loop? Keep your patterns reusable outside the loop:

Pattern pattern = Pattern.compile(Pattern.quote("example"), Pattern.CASE_INSENSITIVE); for(String input : inputList) { String result = pattern.matcher(input).replaceAll("sample"); // Every "example" in the list now has a "sample" makeover. }

Cuts down overhead with every loop iteration and your garbage collector will thank you.

Operating without regex

Going rogue and wanna ditch regex entirely? Loop and replace with StringBuilder and toLowerCase:

StringBuilder sb = new StringBuilder(inputString.toLowerCase()); String targetLower = targetString.toLowerCase(); int index = sb.indexOf(targetLower); // Who needs regex when you've got good ol' loops? while(index != -1) { sb.replace(index, index + targetLower.length(), replacementString); index += replacementString.length(); index = sb.indexOf(targetLower, index); // All aboard the replacement train! } String result = sb.toString().trim();

Performance considerations

Mind the performance costs if working with large strings or frequent operations. Tweak and measure for your scenario. May the performance be with you!

Alternatives and their trade-offs

Third-party libraries might look tempting, but JDK wins the trophy for better control and security. Remember, with great libraries comes great responsibility (and potentially vulnerabilities).

Test in variety

Test your method inside and out; in summer and winter; during the peaks and troughs. The universe of strings is vast - special characters, different case patterns, and performance loads await to be conquered!

Using StringBuffer for synchronized serenity

Craving thread safety? Swap StringBuilder for a StringBuffer. Same club, different perks - StringBuffer delivers synchronized methods.

StringBuffer sb = new StringBuffer("Example"); // Thread-safety guaranteed. No race conditions were harmed in the making of this code snippet.

Towards infinite, but responsibly

Keep an eye on the horizon, but avoid running off the edge. Brilliant loops could turn infinitely reckless minus checks and updates.

Comparisons on an equal platform

Case-insensitive comparison? Chill and use equalsIgnoreCase:

if(str1.equalsIgnoreCase(str2)) { // Just a couple of strings enjoying equality, irrespective of their casing. }

Remembering the ancestors

JDK 7 and older may not support String.replace() for case-insensitivity out of the box. Keep the solutions outlined here as your trusty fallback.