web-dev-qa-db-fra.com

Comment remplacer des sous-chaînes littérales insensibles à la casse en Java

En utilisant la méthode replace(CharSequence target, CharSequence replacement) dans String, comment puis-je rendre la cible insensible à la casse?

Par exemple, la façon dont cela fonctionne maintenant:

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

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

Comment puis-je faire en sorte que le remplacement (ou s'il existe une méthode plus appropriée) ne respecte pas la casse afin que les deux exemples renvoient "Bar"?

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

Sortie:

Bar

Il est à noter que replaceAll traite le premier argument comme un motif regex, ce qui peut entraîner des résultats inattendus. Pour résoudre ce problème, utilisez également Pattern.quote comme suggéré dans les commentaires.

230
smas

Pas aussi élégant que d’autres approches, mais c’est plutôt solide et facile à suivre, en particulier. pour les personnes plus récentes en Java. Une chose qui me tient à propos de la classe String est la suivante: elle existe depuis très longtemps et bien qu'elle prenne en charge un remplacement global avec regexp et un remplacement global avec Strings (via CharSequences), cette dernière n'a pas de simple paramètre booléen : 'isCaseInsensitive'. Vraiment, vous auriez pensé qu'en ajoutant ce petit commutateur, vous auriez pu éviter tous les problèmes que son absence cause aux débutants, en particulier. Maintenant sur JDK 7, String toujours ne prend pas en charge ce petit ajout! 

En tout cas, je vais arrêter de m'agripper. Pour tous les nouveaux néophytes en particulier, voici votre copier-coller deus ex machina . Comme je l'ai dit, pas aussi élégant et vous ne gagnerez pas de prix de codage astucieux, mais cela fonctionne et est fiable. Tous les commentaires, n'hésitez pas à contribuer. (Oui, je sais, StringBuffer est probablement un meilleur choix pour gérer les lignes de mutation de deux chaînes de caractères, mais il est assez facile d'échanger les 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;
}
11
Matt Campbell

Si vous ne vous souciez pas de l'affaire, alors vous n'avez peut-être pas d'importance si elle rend tout en haut

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

La gestion des expressions rationnelles est assez complexe en raison du fait que certains caractères sont réservés: par exemple, "foo.bar".replaceAll(".") produit une chaîne vide, car le point signifie "n'importe quoi". Si vous voulez remplacer uniquement le point, indiquez le paramètre "\\.".

Une solution plus simple consiste à utiliser des objets StringBuilder pour rechercher et remplacer du texte. Il en faut deux: l’une contenant le texte en version minuscule, tandis que la seconde contient la version originale. La recherche est effectuée sur le contenu en minuscules et l'index détecté remplacera également le texte d'origine.

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

Pour les caractères non-Unicode:

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

J'aime smas 's answer qui utilise replaceAll avec une expression régulière. Si vous devez effectuer le même remplacement plusieurs fois, il est judicieux de pré-compiler l'expression régulière une fois:

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

org.Apache.commons.lang3.StringUtils:

public static String replaceIgnoreCase (Texte de chaîne, String searchString, Chaîne de remplacement)

La casse remplace toutes les occurrences d'une chaîne dans une autre chaîne.

1
Michael

Simplifiez les choses sans les bibliothèques tierces:

    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));
0
gouessej