Wie kann ich die Groß- und Kleinschreibung meines Zeichenfolgenvergleichs nicht berücksichtigen?

111

Ich habe ein Java-Programm erstellt, um zwei Zeichenfolgen zu vergleichen:

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

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

Es wird "Willkommen" angezeigt. Ich verstehe, dass zwischen Groß- und Kleinschreibung unterschieden wird. Mein Problem ist jedoch, dass ich zwei Zeichenfolgen ohne Groß- und Kleinschreibung vergleichen möchte. Dh ich erwarte die Ausgabe hai.

user268018
quelle
3
Wenn Sie wissen, dass zwischen Groß- und Kleinschreibung unterschieden wird, können Sie vor dem Vergleich beide in Klein- oder Großbuchstaben konvertieren.
Fastcodejava
Wenn Sie es verwenden, können s1.equalsIgnoreCase(s2)Sie es möglicherweise nicht überall tun, wo es getan werden muss. Ich schlage vor, dass Sie herausfinden, woher die Zeichenfolge stammt - möglicherweise aus einer Datei, einer Datenbank oder einer Benutzereingabe - und entweder in Groß- oder Kleinbuchstaben konvertieren und weiterhin .equals für den Vergleich verwenden.
H2ONaCl
1
Konvertieren Sie nicht in Klein- / Großbuchstaben (wie in den obigen Kommentaren vorgeschlagen), sondern verwenden Sie den akzeptierten equalsIgnoreCaseAnsatz. Lesen Sie das türkische I-Problem und ähnliche Unicode-Probleme zur Begründung.
Ohad Schneider
1
@OhadSchneider equalsIgnoreCasegibt ohnehin den falschen Wert für Türkisch zurück, da für den Vergleich von "i" und "I" true zurückgegeben wird, obwohl false zurückgegeben werden sollte. Ich vermute also, dass a der richtige CollatorWeg ist , wenn Sie Gebietsschemas berücksichtigen möchten .
Trejkaz
1
@OhadSchneider Ich frage mich. Es heißt, dass das Ausführen pro Zeichen das gleiche Ergebnis liefert, aber das Ausführen von toLowerCase/ toUpperCasefür die gesamte Zeichenfolge und das Ausführen pro Zeichen führt auch zu zwei unterschiedlichen Ergebnissen.
Trejkaz

Antworten:

171
  • Das Beste wäre s1.equalsIgnoreCase(s2): (siehe javadoc )
  • Sie können sie auch in Groß- / Kleinschreibung konvertieren und verwenden s1.equals(s2)
Michael Bavin
quelle
39
Beachten Sie jedoch, dass die beiden Lösungen nicht unbedingt für alle Ländereinstellungen identisch sind. String # equalsIgnoreCase verwendet keine länderspezifischen Gehäuseregeln, während String # toLowerCase und #toUpperCase dies tun.
jarnbjo
1
@jarnbjo Kannst du ein Beispiel geben, wo für diesen Unterschied?
Towi
16
Länderspezifische Fallregeln werden zumindest für Türkisch und Deutsch implementiert. Türkisch behandelt I mit und ohne Punkt als zwei verschiedene Buchstaben, wodurch die Klein- / Großbuchstabenpaare iİ und ıI erstellt werden, während andere Sprachen iI als Paar behandeln und die Buchstaben ı und İ nicht verwenden. Im Deutschen wird der Kleinbuchstabe ß als "SS" großgeschrieben.
jarnbjo
24

String.equalsIgnoreCase ist die praktischste Wahl für einen naiven Vergleich von Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung.

Es ist jedoch gut zu wissen, dass diese Methode weder eine vollständige Fallfaltung noch eine Zerlegung durchführt und daher keine falllose Übereinstimmung gemäß dem Unicode-Standard durchführen kann. Tatsächlich bieten die JDK-APIs keinen Zugriff auf Informationen zu Groß- / Kleinschreibung von Zeichendaten. Daher wird dieser Job am besten an eine bewährte Bibliothek eines Drittanbieters delegiert.

Diese Bibliothek ist eine Intensivstation , und hier ist, wie man ein Dienstprogramm für den Vergleich von Zeichenfolgen ohne Berücksichtigung der Groß- und Kleinschreibung implementieren kann:

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

Ein naiver Vergleich mit String.equalsIgnoreCaseoder String.equalsmit Zeichenfolgen in Groß- oder Kleinschreibung schlägt selbst bei diesem einfachen Test fehl.

(Beachten Sie jedoch, dass der vordefinierte Fallfaltungsgeschmack vom getNFKCCasefoldInstanceGebietsschema unabhängig ist. Für türkische Gebietsschemas ist UCharacter.foldCasemöglicherweise etwas mehr Arbeit erforderlich.)

glänzt
quelle
22

Sie müssen die compareToIgnoreCaseMethode des StringObjekts verwenden.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)es bedeutet str1gleich str2.

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

Jetzt wird ausgegeben: hai

KNU
quelle
5

In der Standard-Java-API haben Sie:

String.CASE_INSENSITIVE_ORDER

Sie müssen also keinen Komparator neu schreiben, wenn Sie Zeichenfolgen mit sortierten Datenstrukturen verwenden möchten.

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

Ist das, was Sie für reine Gleichheitsprüfungen in Ihrem eigenen Code wollen.

Nur um weitere Informationen über alles zu erhalten, was die Gleichheit von Strings in Java betrifft. Die hashCode () -Funktion der java.lang.String-Klasse "unterscheidet zwischen Groß- und Kleinschreibung":

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

Wenn Sie also eine Hashtable / HashMap mit Zeichenfolgen als Schlüssel verwenden möchten und Schlüssel wie "SomeKey", "SOMEKEY" und "somekey" als gleich angesehen werden sollen, müssen Sie Ihre Zeichenfolge in eine andere Klasse einschließen (Sie können sie nicht erweitern String, da es sich um eine letzte Klasse handelt). Zum Beispiel :

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

und dann als solches verwenden:

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

Beachten Sie, dass Sie möglicherweise auch Nullprüfungen durchführen möchten, bevor Sie .equals oder .equalsIgnoreCase ausführen.

Ein Null-String-Objekt kann keine equals-Methode aufrufen.

dh:

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
quelle
1
Hinweis: Die beiden zweiten Anweisungen können kombiniert werden, um dasselbe Ergebnis wie folgt zu erzielen : if (str1 == null || str2 == null) return false;.
LuckyMe
Geänderter Code, um sauberer zu sein, wie oben beschrieben - war ein langer Tag :)
VeenarM
1
Sie können auch die erste Zeile ändern, in if (str1 == str2) return true;der beide Nullen enthalten, und den Fall verkürzen, in dem sich die beiden Zeichenfolgenreferenzen auf dasselbe Zeichenfolgenobjekt beziehen.
Barney
1

Um null sicher zu sein, können Sie verwenden

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

oder

org.apache.commons.lang3.StringUtils.equalsIgnoreCase(CharSequence, CharSequence)
brandstaetter
quelle
-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
quelle