C # büyük / küçük harfe duyarlı olmayan bir operatör var mı?


156

Aşağıdakilerin büyük / küçük harfe duyarlı olduğunu biliyorum:

if (StringA == StringB) {

İki dizeyi duyarsız bir şekilde karşılaştıracak bir operatör var mı?



Birisi bir Sözlük <string, int> için büyük / küçük harfe duyarlı olmayan bir karşılaştırma arayan bu soruya rastlarsa, şu soruya bir göz atın: Genel sözlük için büyük / küçük harf duyarsız erişim
Robotnik

Gerçekten güzel olurdu; ~=Paralel karşılık gelen ==bir büyük / küçük harf duyarsız sürüm olarak tanımlamak için .
eidylon

Microsoft geliştiricileri bunu görürse, csharp'ın sonraki sürümünde büyük / küçük harfe duyarlı olmayan bir operatöre ihtiyaç olduğunu düşünüyorum. Bu string.Equal () uzun.
Rez.Net

Yanıtlar:


288

Bunu dene:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

Ben göreceli bir StackOverflow acemi - bağlantı ekleyerek ne demek istediğinizi açıklayabilir misiniz? MSDN belgelerine mi kastediyorsunuz?
John Feminella

55
Kültüre duyarlı karşılaştırma istiyorsanız, bu yöntemi kullanın. "FILE" ve "file" öğelerinin her ikisinin de kabul edildiğinden emin olmak istiyorsanız, "OrdinalIgnoreCase" kullanın, aksi takdirde kodunuz Türk yerel ayarları gibi yerlerde çalışmayabilir. Daha fazla bilgi için, bkz. Moserware.com/2008/02/does-your-code-pass-turkey-test.html
Jeff Moser

10
Samuel'in neden bahsettiğinden emin değilim ... bu cevap mükemmel. Doğru ve açıklayıcı. Referans gerektirmez. +1
Yelken Judo

3
Argh bu çok korkunç bir ağız dolusu! klavyem yıpranacak. " if A$=B$ then goto 10" Kullanabileceğim günler
geride kaldı

9
@Sanjay Manohar O zaman özel bir operatör yazın - ve daha iyi bir klavye tavsiye ederim.
Rushyo

37

Harflerin durumunu görmezden gelen 2 dizeyi karşılaştırmanın en iyi yolu , bir sıralı yoksayma büyük / küçük harf dizesi karşılaştırmasını belirten String.Equals statik yöntemini kullanmaktır . Bu aynı zamanda en hızlı yoldur, dizeleri küçük veya büyük harfe dönüştürmekten ve daha sonra karşılaştırmaktan çok daha hızlıdır.

Her iki yaklaşımın performansını test ettim ve ordinal görmezden gelme durumu dizesi karşılaştırması 9 kat daha hızlıydı ! Dizeleri küçük veya büyük harfe dönüştürmekten daha güvenilirdir (Türkçe i sorununa bakın). Bu nedenle, dizeleri eşitlikle karşılaştırmak için her zaman String.Equals yöntemini kullanın:

String.Equals(string1, string2, StringComparison.OrdinalIgnoreCase);

Kültüre özgü bir dize karşılaştırması yapmak istiyorsanız, aşağıdaki kodu kullanabilirsiniz:

String.Equals(string1, string2, StringComparison.CurrentCultureIgnoreCase);

İkinci örnekte, geçerli kültürün dize karşılaştırma mantığını kullandığını ve bu da onu ilk örnekte "sıralı yoksayma durumu" karşılaştırmasından daha yavaş hale getirdiğini, bu nedenle kültüre özgü dize karşılaştırma mantığına ihtiyacınız yoksa ve maksimum performanstan sonra, "ordinal ignore case" karşılaştırmasını kullanın.

Daha fazla bilgi için blogumdaki hikayenin tamamını okuyun .


1
Önerme ToLowerveya ToLowerInvariant: sadece bir karşılaştırma yapmak için bellek oluştururlar ve unicode'a yeni karakter setleri eklendikçe başarısız olabilirler. ToUpperTürkçe 'i' yüzünden başarısız olur; hiçbir neden yoktur ToLowerbenzer nedenlerle geleceği başarısız olmaz.
antiduh

@antiduh, yorumunuz için teşekkür ederim. Çoğumuz bu potansiyel sorunların farkındayız, internet üzerinden birçok öğretici Türkçe 'i' örnek olarak veriyor. Yazımda gördüğünüz gibi, ToLowerveya ToLowerInvariantyöntemleri kullanmanızı önermiyorum , sadece String.Equalsyöntemin ne kadar daha verimli olduğunu göstermek istedim .
Pavel Vladov

3
"Çoğumuz bu potansiyel sorunların farkındayız, internet üzerinden birçok öğretici Türkçeye örnek olarak" i "yi veriyor" - yeterli insan yok ve hala cevabınızdaki ikinci cümle olarak bahsediyorsunuz. Dahası, cevabınız asla kullanmamak için yeterli gerekçe içermez - sadece performanstan bahsedersiniz; performans her zaman nihai öncelik değildir. Sonuç olarak, şu anda yardım merkezi yönergelerini ihlal ediyorsunuz; harici sitelere bağlantılar iyidir, ancak içeriği yeterince özetlemediniz (türkçe 'i' sorunu). SO reklam platformunuz değil.
antiduh

20

StringComparerStatik sınıfta, istediğiniz herhangi bir büyük / küçük harf duyarlılığı türü için karşılaştırıcılar döndüren bir dizi özellik vardır :

StringComparer Özellikleri

Örneğin,

StringComparer.CurrentCultureIgnoreCase.Equals(string1, string2)

veya

StringComparer.CurrentCultureIgnoreCase.Compare(string1, string2)

Bu biraz daha temiz string.Equalsveya string.Comparebir alacak aşırı StringComparisonargüman.


15
System.Collections.CaseInsensitiveComparer

veya

System.StringComparer.OrdinalIgnoreCase

Bu uygulamanın tamamını etkiler mi?
GateKiller

3
Bununla ilgili daha fazla bilgiyi nerede bulabilirim? Bu, büyük / küçük harfe duyarlı olmayan bir eşleşme için == kullanabileceğim anlamına mı geliyor?
GateKiller

9
string.Equals(StringA, StringB, StringComparison.CurrentCultureIgnoreCase);

8

veya

if (StringA.Equals(StringB, StringComparison.CurrentCultureIgnoreCase)) {

ancak StringA'nın boş olmadığından emin olmanız gerekir. Yani muhtemelen daha iyi tu kullanımı:

string.Equals(StringA , StringB, StringComparison.CurrentCultureIgnoreCase);

John'un önerdiği gibi

EDIT: hata düzeltildi


4

Kullanabilirsiniz

if (stringA.equals(StringB, StringComparison.CurrentCultureIgnoreCase))

3

Şebeke? HAYIR, ancak dize karşılaştırması büyük / küçük harfe duyarlı olmayacak şekilde kültürünüzü değiştirebileceğinizi düşünüyorum.

// you'll want to change this...
System.Threading.Thread.CurrentThread.CurrentCulture
// and you'll want to custimize this
System.Globalization.CultureInfo.CompareInfo

Dizelerin eşit operatör tarafından karşılaştırılma şeklini değiştireceğinden eminim.


Evet, en azından söylemek gerekirse, tüm dize karşılaştırmalarının büyük / küçük harfe duyarsız olmasını istemiyorsanız yapmak istediğiniz şey değildir. Ama bence eşit operatörün davranışını değiştiriyor.
John Leidegren

3

Sözdizimini basitleştirmek için bir fikir:

public class IgnoreCase
{
    private readonly string _value;

    public IgnoreCase(string s)
    {
        _value = s;
    }

    protected bool Equals(IgnoreCase other)
    {
        return this == other;
    }

    public override bool Equals(object obj)
    {
        return obj != null &&
               (ReferenceEquals(this, obj) || (obj.GetType() == GetType() && this == (IgnoreCase) obj));
    }

    public override int GetHashCode()
    {
        return _value?.GetHashCode() ?? 0;
    }

    public static bool operator ==(IgnoreCase a, IgnoreCase b)
    {
        return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
    }

    public static bool operator !=(IgnoreCase a, IgnoreCase b)
    {
        return !(a == b);
    }

    public static implicit operator string(IgnoreCase s)
    {
        return s._value;
    }

    public static implicit operator IgnoreCase(string s)
    {
        return new IgnoreCase(s);
    }
}

Gibi kullanılabilir:

Console.WriteLine((IgnoreCase) "a" == "b"); // false
Console.WriteLine((IgnoreCase) "abc" == "abC"); // true
Console.WriteLine((IgnoreCase) "Abc" == "aBc"); // true
Console.WriteLine((IgnoreCase) "ABC" == "ABC"); // true

Ben temiz görünümlü kullanım sözdizimi gibi olsa da, biraz yanıltıcı ( IgnoreCasevs IgnoreCaseString) ve belirsiz (Java örtük kutulama vs örtülü boks alır, bu yüzden bu Java orada örtülü döküm geri döküm ile işe yaramaz inanıyorum ). Ve bu, görüntülenen kullanım durumu için birkaç iç içe yöntem çağrısına atlayan her karşılaştırma için çağrı ağacı yürütme ile 2 yeni nesnenin bellek yükünü oluşturur. Bununla birlikte, çoğu durumda performans muhtemelen yeterince iyidir.
Arkaine55

Bu akıllıca bir fikir olsa da, sürdürülebilirlik açısından gerçekten akıllıca değil. Sistemin yerleşik dize türünü kullanmak yerine etkin bir dize türü oluşturuyorsunuz. Bundan sonra gelen programcı bir bakışta neler olduğunu anlamayacak ve sonra size küfredecek. String.Equals () kullanmak o kadar da kötü değildir ve çoğu insan ne yaptığını anlar.
ntcolonel

1

Bu karşılaştırma yöntemlerinin sonunda yazmaya çok alışkınım: , StringComparison.

Böylece bir uzantı yaptım.

namespace System
{   public static class StringExtension
    {
        public static bool Equals(this string thisString, string compareString,
             StringComparison stringComparison)
        {
            return string.Equals(thisString, compareString, stringComparison);
        }
    }
}

thisStringDahili numarayı aramadan önce null değerini kontrol etmeniz gerekeceğini unutmayın .


1
Bu, geçerli .NET Framework sürümlerindeki bu yerleşik yöntemle aynı mıdır? docs.microsoft.com/en-gb/dotnet/api/…
Bernard Vander

1
Öyle görünüyor. Görünüşe göre .net'in sonraki sürümleri bunu şimdi içeriyor.
Valamas

.NET 4.5 ve tüm .NET Core sürümlerinden beri kullanılabilir.
Bernard Vander Beken


0
if (StringA.ToUpperInvariant() == StringB.ToUpperInvariant()) {

İnsanlar ToUpperInvariant () yönteminin ToLowerInvariant () yönteminden daha hızlı olduğunu bildiriyor.


1
Mevcut veya istenen kültürün üst kasa için özel kuralları varsa, değişmez kötü bir fikir olabilir.
OregonGhost

Bu, her dizenin yeni bir kopyasını oluşturuyor mu? Eğer öyleyse, kötü fikir.
cjk

1
Bu, dizelerden biri (veya her ikisi) null olduğunda da bir istisna atar.
tvanfosson

3
Performans açısından, bu da iyi bir çözüm değil, burada da 2 yeni dize örneği oluşturacaksınız.
Frederik Gheysels

0

Diğerlerinin cevabı burada tamamen geçerlidir, ancak bir şekilde yazmak StringComparison.OrdinalIgnoreCaseve kullanmak biraz zaman alır String.Compare.

Karşılaştırma büyük / küçük harf duyarlı veya boolean ile anlamsız olup olmadığını belirtebilirsiniz basit String uzantısı yöntemi kodladım - aşağıdaki cevaba bakın:

https://stackoverflow.com/a/49208128/2338477

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.