Cómo reemplazar subcadenas literales insensibles a mayúsculas y minúsculas en Java

Usando el método replace(CharSequence target, CharSequence replacement) en String, ¿cómo puedo hacer que el objective no replace(CharSequence target, CharSequence replacement) entre mayúsculas y minúsculas?

Por ejemplo, la forma en que funciona en este momento:

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

¿Cómo puedo hacer que sea tan reemplazado (o si hay un método más adecuado) no distingue entre mayúsculas y minúsculas para que ambos ejemplos devuelvan “Bar”?

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

Salida:

 Bar 

Vale la pena mencionar que replaceAll trata el primer argumento como un patrón de replaceAll regulares, que puede causar resultados inesperados. Para resolver esto, también use Pattern.quote como se sugiere en los comentarios.

No tan elegante tal vez como otros enfoques, pero es bastante sólido y fácil de seguir, esp. para las personas más nuevas en Java. Una cosa que me atrapa de la clase String es esta: ha existido durante mucho tiempo y aunque admite un reemplazo global con regexp y un reemplazo global con Strings (a través de CharSequences), este último no tiene un parámetro booleano simple : ‘isCaseInsensitive’. En realidad, habrías pensado que con solo agregar un pequeño interruptor, se podrían haber evitado todos los problemas que su ausencia causa a los principiantes. ¡Ahora en JDK 7, String todavía no admite esta pequeña adición!

Bueno, de todos modos, dejaré de quejarte. Para todos, en particular, los más nuevos de Java, aquí está su deus ex machina de cortar y pegar. Como dije, no es tan elegante y no le ganará premios de encoding ingeniosos, pero funciona y es confiable. Cualquier comentario, no dude en contribuir. (Sí, lo sé, StringBuffer es probablemente una mejor opción para administrar las líneas de mutación de cadena de dos caracteres, pero es bastante fácil intercambiar las 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; } 

Las expresiones regulares son bastante complejas de administrar debido al hecho de que algunos caracteres están reservados: por ejemplo, "foo.bar".replaceAll(".") Produce una cadena vacía, porque el punto significa “cualquier cosa” Si desea reemplazar solo el punto debe indicarse como un parámetro "\\." .

Una solución más simple es usar objetos StringBuilder para buscar y reemplazar texto. Toma dos: uno que contiene el texto en minúscula mientras que el segundo contiene la versión original. La búsqueda se realiza en los contenidos en minúscula y el índice detectado también reemplazará el 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", "*")); } } 

Si no te importa el caso, entonces quizás no importe si devuelve todo en mayúsculas:

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

Me gusta la respuesta de replaceAll que usa replaceAll con una expresión regular. Si va a hacer el mismo reemplazo muchas veces, tiene sentido precomstackr la expresión regular una 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 que no son Unicode:

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

org.apache.commons.lang3.StringUtils:

public static String replaceIgnoreCase (texto de cadena, String searchString, reemplazo de cadena)

Case insensiblemente reemplaza todas las ocurrencias de una Cadena dentro de otra Cadena.