Como replace subseqüências literais insensíveis a maiúsculas e minúsculas em Java

Usando o método replace(CharSequence target, CharSequence replacement) em String, como posso tornar o destino insensível a maiúsculas e minúsculas?

Por exemplo, a maneira como funciona agora:

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

Como posso fazer isso para replace (ou se houver um método mais adequado) é insensível a maiúsculas e minúsculas para que ambos os exemplos retornem “Bar”?

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

Saída:

 Bar 

Vale a pena mencionar que replaceAll trata o primeiro argumento como um padrão regex, que pode causar resultados inesperados. Para resolver isso, use também Pattern.quote como sugerido nos comentários.

Não é tão elegante como outras abordagens, mas é bastante sólido e fácil de seguir, esp. para pessoas mais novas em Java. Uma coisa que me faz falar sobre a class String é: ela existe há muito tempo e suporta uma substituição global com regexp e uma substituição global por Strings (via CharSequences), que não possui um parâmetro booleano simples : ‘isCaseInsensitive’. Realmente, você teria pensado que apenas adicionando aquele pequeno interruptor, todo o problema que sua ausência causa para os iniciantes, especialmente poderia ter sido evitado. Agora no JDK 7, String ainda não suporta essa pequena adição!

Bem, de qualquer maneira, eu vou parar de reclamar. Para todos os que são mais novos em Java, aqui está o seu deus de cortar e colar. Como eu disse, não é tão elegante e não vai ganhar nenhum prêmio de codificação, mas funciona e é confiável. Qualquer comentário, fique à vontade para contribuir. (Sim, eu sei, StringBuffer é provavelmente a melhor escolha para gerenciar as linhas de mutação de duas cadeias de caracteres, mas é fácil trocar as técnicas.)

 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; } 

Expressões regulares são bastante complexas para gerenciar devido ao fato de que alguns caracteres são reservados: por exemplo, "foo.bar".replaceAll(".") Produz uma string vazia, porque o ponto significa “qualquer coisa” Se você deseja replace apenas o ponto deve ser indicado como um parâmetro "\\." .

Uma solução mais simples é usar objects StringBuilder para pesquisar e replace texto. Leva dois: um que contém o texto em versão minúscula enquanto o segundo contém a versão original. A pesquisa é realizada no conteúdo em minúsculas e o índice detectado também replaceá o texto original.

 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", "*")); } } 

Se você não se importa com o caso, então talvez não importe se ele retorna todo upcase:

 target.toUpperCase().replace("FOO", ""); 

Eu gosto da resposta do replaceAll que usa replaceAll com uma expressão regular. Se você vai fazer a mesma substituição muitas vezes, faz sentido pré-compilar a expressão regular uma vez:

 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")); } } 

Para caracteres não-Unicode:

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

org.apache.commons.lang3.StringUtils:

public static String replaceIgnoreCase (String de texto, String searchString, substituição de String)

O caso insensivelmente substitui todas as ocorrências de uma String dentro de outra String.