Come faccio a rendere insensibile al maiuscolo e minuscolo il confronto tra stringhe?


111

Ho creato un programma Java per confrontare due stringhe:

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

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

Visualizza "benvenuto". Capisco che fa distinzione tra maiuscole e minuscole. Ma il mio problema è che voglio confrontare due stringhe senza distinzione tra maiuscole e minuscole. Cioè mi aspetto che l'output sia hai.


3
Se sai che fa distinzione tra maiuscole e minuscole, puoi convertirli entrambi in minuscolo o maiuscolo prima del confronto.
fastcodejava

se lo usi s1.equalsIgnoreCase(s2)potresti non riuscire a farlo ovunque deve essere fatto. Ti suggerisco di trovare da dove proviene la stringa - un file o un database o l'input dell'utente forse - e convertirla in maiuscolo (o minuscolo) e continuare a utilizzare .equals per il confronto.
H2ONaCl

2
Non convertire in minuscolo / maiuscolo (come suggerito dai commenti sopra), usa l' equalsIgnoreCaseapproccio accettato . Leggi il problema turco I e problemi Unicode simili per la logica.
Ohad Schneider

1
@OhadSchneider equalsIgnoreCaserestituisce comunque il valore sbagliato per il turco, perché restituisce true per il confronto "i" e "I", anche se dovrebbe restituire false. Quindi sospetto che se vuoi prendere in considerazione le impostazioni locali, a Collatorè effettivamente la strada da percorrere.
Trejkaz

1
@OhadSchneider mi chiedo. Dice che farlo per carattere produce lo stesso risultato, ma fare toLowerCase/ toUpperCasesull'intera stringa e farlo per carattere danno anche due risultati diversi.
Trejkaz

Risposte:


171
  • Il migliore sarebbe usare s1.equalsIgnoreCase(s2): (vedi javadoc )
  • Puoi anche convertirli entrambi in maiuscolo / minuscolo e usare s1.equals(s2)

39
Tieni presente che le due soluzioni non sono necessariamente identiche per tutte le impostazioni locali. String # equalsIgnoreCase non usa regole di maiuscole / minuscole specifiche della locale, mentre String # toLowerCase e #toUpperCase lo fanno.
jarnbjo

1
@jarnbjo Puoi fare un esempio dove per quella differenza?
verso

16
Le regole del caso specifico delle impostazioni locali sono almeno implementate per turco e tedesco. Il turco tratta I con e senza punto come due lettere diverse, creando le coppie minuscole / maiuscole iİ e ıI mentre le altre lingue trattano iI come una coppia e non usano le lettere ı e İ. In tedesco, la ß minuscola è maiuscola come "SS".
jarnbjo


24

String.equalsIgnoreCase è la scelta più pratica per il confronto ingenuo di stringhe senza distinzione tra maiuscole e minuscole.

Tuttavia, è bene essere consapevoli del fatto che questo metodo non esegue né il ripiegamento completo delle maiuscole né la scomposizione e quindi non può eseguire la corrispondenza senza maiuscole come specificato nello standard Unicode. In effetti, le API JDK non forniscono l'accesso alle informazioni sui dati dei caratteri di piegatura dei casi, quindi è meglio delegare questo lavoro a una libreria di terze parti collaudata.

Quella libreria è ICU , ed ecco come si potrebbe implementare un'utilità per il confronto di stringhe senza distinzione tra maiuscole e minuscole:

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

Un confronto ingenuo con String.equalsIgnoreCase, o String.equalssu stringhe in maiuscolo o minuscolo fallirà anche questo semplice test.

(Si noti, tuttavia, che il sapore predefinito di piegatura delle maiuscole getNFKCCasefoldInstanceè indipendente dalle impostazioni locali; per le lingue turche UCharacter.foldCasepotrebbe essere necessario un po 'più di lavoro che coinvolga .)


22

Devi usare il compareToIgnoreCasemetodo Stringdell'oggetto.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)significa str1uguale str2.


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

Ora produrrà: hai


5

Nell'API Java predefinita hai:

String.CASE_INSENSITIVE_ORDER

Quindi non è necessario riscrivere un comparatore se si utilizzassero stringhe con strutture dati ordinate.

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

È quello che vuoi per i controlli di uguaglianza puri nel tuo codice.

Solo per ulteriori informazioni su tutto ciò che riguarda l'uguaglianza delle stringhe in Java. La funzione hashCode () della classe java.lang.String "distingue tra maiuscole e minuscole":

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

Quindi, se vuoi usare una Hashtable / HashMap con stringhe come chiavi e avere chiavi come "SomeKey", "SOMEKEY" e "somekey" sono considerate uguali, allora dovrai racchiudere la tua stringa in un'altra classe (non puoi estendere String poiché è una classe finale). Per esempio :

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

e poi usalo come tale:

HashMap<HashWrap, Object> map = new HashMap<HashWrap, Object>();

2

Nota che potresti voler eseguire controlli nulli anche su di essi prima di eseguire il tuo .equals o .equalsIgnoreCase.

Un oggetto String null non può chiamare un metodo equals.

vale a 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);
}

1
Nota: secondo due affermazioni possono essere combinati per produrre lo stesso risultato come questo: if (str1 == null || str2 == null) return false;.
LuckyMe

Codice modificato per essere più pulito come da commento sopra - è stata una giornata lunga :)
VeenarM

1
È inoltre possibile modificare la prima riga a if (str1 == str2) return true;cui entrambi si rivolge a null e anche scorciatoie il caso in cui i due riferimenti di stringa si riferiscono allo stesso oggetto stringa.
Barney




1

Per essere nullsafe, puoi usare

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

o

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)

-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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.