161

Using the method replace(CharSequence target, CharSequence replacement) in String, how can I make the target case-insensitive?

For example, the way it works right now:

String target = "FooBar";
target.replace("Foo", "") // would return "Bar"

String target = "fooBar";
target.replace("Foo", "") // would return "fooBar"

How can I make it so replace (or if there is a more suitable method) is case-insensitive so that both examples return "Bar"?

Glenn Teitelbaum
  • 10,108
  • 3
  • 36
  • 80
J. Lin
  • 2,259
  • 5
  • 20
  • 17

10 Answers10

360
String target = "FOOBar";
target = target.replaceAll("(?i)foo", "");
System.out.println(target);

Output:

Bar

It's worth mentioning that replaceAll treats the first argument as a regex pattern, which can cause unexpected results. To solve this, also use Pattern.quote as suggested in the comments.

Community
  • 1
  • 1
lukastymo
  • 26,145
  • 14
  • 53
  • 66
  • 1
    What if target contains $ or diacritical characters like á? – stracktracer Apr 05 '12 at 07:21
  • what do you mean? target=FOOBará, after replacing in above way output is: Bará – lukastymo Apr 05 '12 at 07:31
  • 3
    I mean two things: 1. "blÁÜ123".replaceAll("(?i)bláü") does not replace anything. 2. "Sentence!End".replaceAll("(?i)Sentence.") does maybe replace more than anticipated. – stracktracer Apr 11 '12 at 11:54
  • 1
    You can't turn string into regex matching it so simple. It's not correct generally, it will work only for specific cases. – Danubian Sailor Jan 23 '14 at 11:18
  • @smas Is it regex java syntax? – gstackoverflow Apr 17 '14 at 09:23
  • 26
    Use Pattern.quote() to protect the search string from being interpreted as a regex. This doe snot address the unicode quirks listed above, but should be fine for basic character sets. e.g. `target.replaceAll("(?i)"+Pattern.quote("foo"), "");` – Jeff Adamson Jun 23 '15 at 20:19
  • Awesome, This is working with only only `replaceAll` and `replaceFirst` – Pratik Butani Oct 29 '15 at 16:22
  • 1
    Just making sure. Pattern.quote("foo") is not necessary if the string is "foo" right? Only if it is something more fancy, right? – ed22 Aug 23 '17 at 11:05
13

Just make it simple without third party libraries:

    final String source = "FooBar";
    final String target = "Foo";
    final String replacement = "";
    final String result = Pattern.compile(target, Pattern.LITERAL | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE).matcher(source)
.replaceAll(Matcher.quoteReplacement(replacement));
gouessej
  • 3,640
  • 3
  • 33
  • 67
12

Regular expressions are quite complex to manage due to the fact that some characters are reserved: for example, "foo.bar".replaceAll(".") produces an empty string, because the dot means "anything" If you want to replace only the point should be indicated as a parameter "\\.".

A simpler solution is to use StringBuilder objects to search and replace text. It takes two: one that contains the text in lowercase version while the second contains the original version. The search is performed on the lowercase contents and the index detected will also replace the original text.

public class LowerCaseReplace 
{
    public static String replace(String source, String target, String replacement)
    {
        StringBuilder sbSource = new StringBuilder(source);
        StringBuilder sbSourceLower = new StringBuilder(source.toLowerCase());
        String searchString = target.toLowerCase();

        int idx = 0;
        while((idx = sbSourceLower.indexOf(searchString, idx)) != -1) {
            sbSource.replace(idx, idx + searchString.length(), replacement);
            sbSourceLower.replace(idx, idx + searchString.length(), replacement);
            idx+= replacement.length();
        }
        sbSourceLower.setLength(0);
        sbSourceLower.trimToSize();
        sbSourceLower = null;

        return sbSource.toString();
    }


    public static void main(String[] args)
    {
        System.out.println(replace("xXXxyyyXxxuuuuoooo", "xx", "**"));
        System.out.println(replace("FOoBaR", "bar", "*"));
    }
}
ilmassa
  • 121
  • 1
  • 2
12

If you don't care about case, then you perhaps it doesn't matter if it returns all upcase:

target.toUpperCase().replace("FOO", "");
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • You can also pass the Locale into toUpperCase(locale) if your dealing with characters like á. – rob Apr 24 '13 at 15:09
9

Not as elegant perhaps as other approaches but it's pretty solid and easy to follow, esp. for people newer to Java. One thing that gets me about the String class is this: It's been around for a very long time and while it supports a global replace with regexp and a global replace with Strings (via CharSequences), that last doesn't have a simple boolean parameter: 'isCaseInsensitive'. Really, you'd've thought that just by adding that one little switch, all the trouble its absence causes for beginners especially could have been avoided. Now on JDK 7, String still doesn't support this one little addition!

Well anyway, I'll stop griping. For everyone in particular newer to Java, here's your cut-and-paste deus ex machina. As I said, not as elegant and won't win you any slick coding prizes, but it works and is reliable. Any comments, feel free to contribute. (Yes, I know, StringBuffer is probably a better choice of managing the two character string mutation lines, but it's easy enough to swap the techniques.)

public String replaceAll(String findtxt, String replacetxt, String str, 
        boolean isCaseInsensitive) {
    if (str == null) {
        return null;
    }
    if (findtxt == null || findtxt.length() == 0) {
        return str;
    }
    if (findtxt.length() > str.length()) {
        return str;
    }
    int counter = 0;
    String thesubstr = "";
    while ((counter < str.length()) 
            && (str.substring(counter).length() >= findtxt.length())) {
        thesubstr = str.substring(counter, counter + findtxt.length());
        if (isCaseInsensitive) {
            if (thesubstr.equalsIgnoreCase(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                // Failing to increment counter by replacetxt.length() leaves you open
                // to an infinite-replacement loop scenario: Go to replace "a" with "aa" but
                // increment counter by only 1 and you'll be replacing 'a's forever.
                counter += replacetxt.length();
            } else {
                counter++; // No match so move on to the next character from
                           // which to check for a findtxt string match.
            }
        } else {
            if (thesubstr.equals(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                counter += replacetxt.length();
            } else {
                counter++;
            }
        }
    }
    return str;
}
Danubian Sailor
  • 1
  • 38
  • 145
  • 223
Matt Campbell
  • 1,967
  • 1
  • 22
  • 34
4

For non-Unicode characters:

String result = Pattern.compile("(?i)препарат", 
Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");
4

org.apache.commons.lang3.StringUtils:

public static String replaceIgnoreCase(String text, String searchString, String replacement)

Case insensitively replaces all occurrences of a String within another String.

Michael
  • 192
  • 1
  • 5
3

I like smas's answer that uses replaceAll with a regular expression. If you are going to be doing the same replacement many times, it makes sense to pre-compile the regular expression once:

import java.util.regex.Pattern;

public class Test { 

    private static final Pattern fooPattern = Pattern.compile("(?i)foo");

    private static removeFoo(s){
        if (s != null) s = fooPattern.matcher(s).replaceAll("");
        return s;
    }

    public static void main(String[] args) {
        System.out.println(removeFoo("FOOBar"));
    }
}
Community
  • 1
  • 1
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
1

I know it's an old question but with Apache's StringUtils it's pretty simple:

String target = "FooBar";
StringUtils.replaceIgnoreCase(target , "bar", "");
// Output: Foo

Here's maven dep.

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>
adex
  • 75
  • 10
-1
String newstring  = "";
String target2 = "fooBar";
newstring = target2.substring("foo".length()).trim();   
logger.debug("target2: {}",newstring); 
// output: target2: Bar
    
String target3 = "FooBar";
newstring = target3.substring("foo".length()).trim();
logger.debug("target3: {}",newstring); 
// output: target3: Bar
Asaf Magen
  • 862
  • 10
  • 22