Comment rendre ma comparaison de chaînes insensible à la casse?

111

J'ai créé un programme Java pour comparer deux chaînes:

String s1 = "Hello";
String s2 = "hello";

if (s1.equals(s2)) {
    System.out.println("hai");
} else {
    System.out.println("welcome");
}

Il affiche "bienvenue". Je comprends que c'est sensible à la casse. Mais mon problème est que je souhaite comparer deux chaînes sans respecter la casse. Ie je m'attends à ce que la sortie soit hai.

user268018
la source
3
Si vous savez qu'il est sensible à la casse, vous pouvez convertir les deux en minuscules ou en majuscules avant de comparer.
fastcodejava
si vous utilisez, s1.equalsIgnoreCase(s2)vous risquez de ne pas le faire partout où cela doit être fait. Je suggère que vous trouviez d'où vient la chaîne - un fichier ou une base de données ou une entrée utilisateur peut-être - et que vous la convertissiez en majuscules (ou en minuscules) et que vous continuiez à utiliser .equals pour la comparaison.
H2ONaCl
2
Ne pas convertir en minuscules / majuscules (comme suggéré par les commentaires ci-dessus), utilisez l' equalsIgnoreCaseapproche acceptée . Renseignez-vous sur le problème turc I et les problèmes Unicode similaires pour la justification.
Ohad Schneider
1
@OhadSchneider equalsIgnoreCaserenvoie de toute façon la mauvaise valeur pour le turc, car il renvoie true pour comparer "i" et "I", même s'il doit renvoyer false. Donc je soupçonne que si vous voulez prendre en compte les paramètres régionaux, Collatorc'est en fait la voie à suivre.
Trejkaz
1
@OhadSchneider je me demande. Cela dit que le faire par caractère produit le même résultat, mais faire toLowerCase/ toUpperCasesur toute la chaîne et le faire par caractère donne également deux résultats différents.
Trejkaz

Réponses:

171
  • Le mieux serait d'utiliser s1.equalsIgnoreCase(s2): (voir javadoc )
  • Vous pouvez également les convertir en majuscules / minuscules et utiliser s1.equals(s2)
Michael Bavin
la source
39
Sachez simplement que les deux solutions ne sont pas nécessairement identiques pour tous les paramètres régionaux. String # equalsIgnoreCase n'utilise pas de règles de casse spécifiques aux paramètres régionaux, contrairement à String # toLowerCase et #toUpperCase.
jarnbjo
1
@jarnbjo Pouvez-vous donner un exemple d'où cette différence?
towi
16
Les règles de cas spécifiques aux paramètres régionaux sont au moins implémentées pour le turc et l'allemand. Le turc traite I avec et sans point comme deux lettres différentes, créant les paires minuscules / majuscules iİ et ıI tandis que d'autres langues traitent iI comme une paire et n'utilisent pas les lettres ı et İ. En allemand, la minuscule ß est en majuscule "SS".
jarnbjo
24

String.equalsIgnoreCase est le choix le plus pratique pour la comparaison naïve de chaînes insensible à la casse.

Cependant, il est bon de savoir que cette méthode ne fait ni pliage ni décomposition complet de la casse et ne peut donc pas effectuer de correspondance sans casse comme spécifié dans la norme Unicode.En fait, les API JDK ne fournissent pas d'accès aux informations sur les données de caractères de pliage de cas, il est donc préférable de déléguer ce travail à une bibliothèque tierce éprouvée.

Cette bibliothèque est ICU , et voici comment implémenter un utilitaire pour la comparaison de chaînes insensible à la casse:

import com.ibm.icu.text.Normalizer2;

// ...

public static boolean equalsIgnoreCase(CharSequence s, CharSequence t) {
    Normalizer2 normalizer = Normalizer2.getNFKCCasefoldInstance();
    return normalizer.normalize(s).equals(normalizer.normalize(t));
}
    String brook = "flu\u0308ßchen";
    String BROOK = "FLÜSSCHEN";

    assert equalsIgnoreCase(brook, BROOK);

Comparaison naïve avec String.equalsIgnoreCase, ouString.equals sur des chaînes majuscules ou minuscules échouera même ce test simple.

(Notez cependant que la saveur prédéfinie de pliage de cas getNFKCCasefoldInstanceest indépendante des paramètres régionaux; pour les paramètres régionaux turcs, un peu plus de travail UCharacter.foldCasepeut être nécessaire.)

glts
la source
22

Vous devez utiliser la compareToIgnoreCaseméthode de l' Stringobjet.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)cela signifie str1égal str2.

Aliti
la source
10
import java.lang.String; //contains equalsIgnoreCase()
/*
*
*/
String s1 = "Hello";
String s2 = "hello";

if (s1.equalsIgnoreCase(s2)) {
System.out.println("hai");
} else {
System.out.println("welcome");
}

Maintenant, il affichera: hai

KNU
la source
5

Dans l'API Java par défaut, vous avez:

String.CASE_INSENSITIVE_ORDER

Vous n'avez donc pas besoin de réécrire un comparateur si vous deviez utiliser des chaînes avec des structures de données triées.

String s = "some text here";
s.equalsIgnoreCase("Some text here");

C'est ce que vous voulez pour des vérifications d'égalité pure dans votre propre code.

Juste pour plus d'informations sur tout ce qui concerne l'égalité des chaînes en Java. La fonction hashCode () de la classe java.lang.String "est sensible à la casse":

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

Donc, si vous voulez utiliser un Hashtable / HashMap avec des chaînes comme clés, et que des clés telles que "SomeKey", "SOMEKEY" et "somekey" soient considérées comme égales, vous devrez alors envelopper votre chaîne dans une autre classe (vous ne pouvez pas étendre String puisqu'il s'agit d'une classe finale). Par exemple :

private static class HashWrap {
    private final String value;
    private final int hash;

    public String get() {
        return value;
    }

    private HashWrap(String value) {
        this.value = value;
        String lc = value.toLowerCase();
        this.hash = lc.hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof HashWrap) {
            HashWrap that = (HashWrap) o;
            return value.equalsIgnoreCase(that.value);
        } else {
            return false;
        }
    }

    @Override
    public int hashCode() {
        return this.hash;
    }
}

puis utilisez-le comme tel:

HashMap<HashWrap, Object> map = new HashMap<HashWrap, Object>();
le-doude
la source
2

Notez que vous souhaiterez peut-être effectuer des vérifications nulles sur eux également avant de faire vos .equals ou .equalsIgnoreCase.

Un objet String nul ne peut pas appeler une méthode equals.

c'est à dire:

public boolean areStringsSame(String str1, String str2)
{
    if (str1 == null && str2 == null)
        return true;
    if (str1 == null || str2 == null)
        return false;

    return str1.equalsIgnoreCase(str2);
}
VeenarM
la source
1
Remarque: deuxième deux déclarations peuvent être combinées pour produire même résultat comme celui - ci: if (str1 == null || str2 == null) return false;.
LuckyMe
Code modifié pour être plus propre selon le commentaire ci-dessus - c'était une longue journée :)
VeenarM
1
Vous pouvez également modifier la première ligne à if (str1 == str2) return true;laquelle les deux traitent les valeurs nulles et raccourcit également le cas où les deux références de chaîne font référence au même objet de chaîne.
Barney
1

Pour être nullsafe, vous pouvez utiliser

org.apache.commons.lang.StringUtils.equalsIgnoreCase(String, String)

ou

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)
brandstaetter
la source
-6
public boolean newEquals(String str1, String str2)
{
    int len = str1.length();
int len1 = str2.length();
if(len==len1)
{
    for(int i=0,j=0;i<str1.length();i++,j++)
    {
        if(str1.charAt(i)!=str2.charAt(j))
        return false;
    }`enter code here`
}
return true;
}
Javacoder
la source