Dize karşılaştırma büyük / küçük harf duyarlılığımı nasıl duyarsız hale getirebilirim?


111

İki dizeyi karşılaştırmak için bir Java programı oluşturdum:

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

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

"Hoş Geldiniz" ibaresini görüntüler. Büyük / küçük harfe duyarlı olduğunu anlıyorum. Ama benim sorunum, iki dizgeyi büyük / küçük harf duyarlılığı olmadan karşılaştırmak istemem. Yani çıktının olmasını bekliyorum hai.


3
Büyük / küçük harfe duyarlı olduğunu biliyorsanız, karşılaştırmadan önce her ikisini de küçük harfe veya büyük harfe dönüştürebilirsiniz.
fastcodejava

Eğer kullanırsanız, s1.equalsIgnoreCase(s2)yapılması gereken her yerde yapamayabilirsiniz. Dizenin nereden geldiğini bulmanızı (bir dosya veya veritabanı veya kullanıcı girişi) bulmanızı ve büyük harfe (veya küçük harfe) dönüştürmenizi ve karşılaştırma için .equals kullanmaya devam etmenizi öneririm.
H2ONaCl

2
Küçük / büyük harfe dönüştürmeyin (yukarıdaki yorumlarda önerildiği gibi), kabul edilen equalsIgnoreCaseyaklaşımı kullanın . Gerekçe için Türkçe I sorunu ve benzer Unicode sorunları hakkında bilgi edinin.
Ohad Schneider

1
@OhadSchneider equalsIgnoreCaseyine de Türkçe için yanlış değeri döndürüyor, çünkü "i" ve "I" yi karşılaştırmak için true döndürüyor, yanlış döndürmesi gerekse bile. Bu nedenle, yerel ayarları hesaba katmak istiyorsanız, a'nın Collatoraslında gidilecek yol olduğundan şüpheleniyorum .
Trejkaz

1
@OhadSchneider merak ediyorum. Bunu karakter başına yapmanın aynı sonucu verdiğini söylüyor, ancak tüm dizge üzerinde yapmak toLowerCase/ toUpperCaseyapmak ve karakter başına yapmak da iki farklı sonuç veriyor.
Trejkaz

Yanıtlar:


171
  • En iyisi kullanmaktır s1.equalsIgnoreCase(s2): (bkz. Javadoc )
  • Bunları hem büyük / küçük harfe dönüştürebilir hem de s1.equals(s2)

39
Sadece iki çözümün tüm yerel ayarlar için aynı olmadığını unutmayın. String # equalsIgnoreCase yerel ayara özgü büyük / küçük harf kurallarını kullanmazken, String # toLowerCase ve #toUpperCase bunu yapar.
jarnbjo

1
@jarnbjo Bu farkın neresine bir örnek verebilir misiniz?
towi

16
Yerel özel durum kuralları en azından Türkçe ve Almanca için uygulanmaktadır. Türkçe I'yi noktalı ve noktasız olarak iki farklı harf olarak ele alır, küçük / büyük harf çiftleri iİ ve ıI oluştururken, diğer diller iI'yi bir çift olarak ele alır ve ı ve İ harflerini kullanmaz. Almanca'da küçük harf olan ß "SS" olarak büyük harfle yazılır.
jarnbjo


24

String.equalsIgnoreCase naif büyük / küçük harfe duyarlı olmayan dize karşılaştırması için en pratik seçimdir.

Bununla birlikte, bu yöntemin ne tam büyük / küçük harf bölme ne de ayrıştırma yapmadığını ve dolayısıyla Unicode standardında belirtildiği gibi büyük harfsiz eşleştirme gerçekleştiremediğini bilmekte fayda var. Aslında, JDK API'leri büyük / küçük harf katlama karakter verileriyle ilgili bilgilere erişim sağlamaz, bu nedenle bu iş en iyi şekilde denenmiş ve test edilmiş bir üçüncü taraf kitaplığına devredilir.

Bu kütüphane, ICU'dur ve işte, büyük / küçük harfe duyarlı olmayan dize karşılaştırması için bir yardımcı program nasıl uygulanabilir:

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

String.equalsIgnoreCaseVeya ile saf karşılaştırmaString.equals veya küçük harfli dizelerle veya bu dizeler üzerinde saf bu basit testte bile başarısız olacaktır.

(Önceden tanımlanmış kasa katlama çeşidinin getNFKCCasefoldInstanceyerel ayardan bağımsız olduğuna dikkat edin ; Türk yerelleri için biraz daha fazla çalışma UCharacter.foldCasegerekli olabilir.)


22

Nesnenin compareToIgnoreCaseyöntemini kullanmalısınız String.

int compareValue = str1.compareToIgnoreCase(str2);

if (compareValue == 0)str1eşittir demektir 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");
}

Şimdi çıktı: hai


5

Varsayılan Java API'sinde sahip olduğunuz:

String.CASE_INSENSITIVE_ORDER

Dolayısıyla, Sıralanmış veri yapılarıyla dizeler kullanacaksanız, bir karşılaştırıcıyı yeniden yazmanıza gerek yoktur.

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

Kendi kodunuzda saf eşitlik kontrolleri için istediğiniz şey budur.

Sadece Java'daki Dizelerin eşitliği ile ilgili herhangi bir şey hakkında daha fazla bilgi için. Java.lang.String sınıfının hashCode () işlevi "büyük / küçük harfe duyarlıdır":

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

Dolayısıyla, Dizeler içeren bir Hashtable / HashMap'i anahtar olarak kullanmak istiyorsanız ve "SomeKey", "SOMEKEY" ve "somekey" gibi anahtarların eşit görülmesini istiyorsanız, o zaman dizenizi başka bir sınıfa kaydırmanız gerekir (genişletemezsiniz) String, son sınıf olduğu için). Örneğin :

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

ve sonra şu şekilde kullanın:

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

2

.Equals veya .equalsIgnoreCase işlemlerinizi yapmadan önce bunlarda da boş kontroller yapmak isteyebileceğinizi unutmayın.

Boş bir String nesnesi, eşittir yöntemini çağıramaz.

yani:

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
Not: İkinci iki ifade böyle aynı sonucu üretmek için birleştirilebilir: if (str1 == null || str2 == null) return false;.
luckyme

Kod, yukarıdaki yoruma göre daha temiz olacak şekilde değiştirildi - uzun bir gündü :)
VeenarM

1
Ayrıca, if (str1 == str2) return true;hem boş değerleri içeren ilk satırı hem de iki dize başvurusunun aynı dize nesnesine başvurduğu durumda kısayollar olan ilk satırı da değiştirebilirsiniz .
Barney




1

Nullsafe olmak için kullanabilirsiniz

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

veya

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.