InvariantCulture ve Ordinal dize karşılaştırması arasındaki fark


548

Eşitlik için c # 'daki iki dizeyi karşılaştırırken, InvariantCulture ve Ordinal karşılaştırma arasındaki fark nedir?



2
Kullananlar için String1.Equals(String2, StringComparison.Ordinal), String1 == String2kendinden daha iyi kullanırsınız String1.Equals(String2)ve varsayılan olarak sıra büyüklüğüne duyarlı bir karşılaştırmadır.
Ghasan

3
@Ghasan Bunun =="daha iyi" olup olmadığından emin değilim , ama a) daha kısa, b) tam olarak ne yaptığı hakkında daha az açık ve c) String1karşılaştırma atmadan boş olabilir NullReferenceException.
Eugene Beresovsky

3
@Ghasan, .NET Framework sayfasındaki ( msdn.microsoft.com/en-us/library/… ) Dizeleri Kullanmak İçin Resmi MSDN En İyi Yöntemlerini açıkça belirten aşırı yüklerin kullanılmasını önerir StringComparison. Dize karşılaştırması durumunda, bu demektir String.Equals.
Ohad Schneider

3
@EugeneBeresovsky önlemek için NullReferenceExceptionsadece statik yöntemi kullanabilirsiniz: String.Equals(string1, string2, StringComparison.Ordinal).
Ohad Schneider

Yanıtlar:


302

InvariantCulture

"Standart" karakter sıralaması kullanır (a, b, c, ... vb.). Bu, karakterleri farklı sıralarda sıralayabilen bazı belirli yerel ayarların tersidir ('a-with-akut' , yerel ayara bağlı olarak 'a'dan önce veya sonra olabilir vb.).

sıra

Öte yandan, sadece karakteri temsil eden ham bayt (lar) ın değerlerine bakar.


Http://msdn.microsoft.com/en-us/library/e6883c06.aspx adresinde çeşitli StringComparison değerlerinin sonuçlarını gösteren harika bir örnek vardır . Sonunda, gösterir (alıntı):

StringComparison.InvariantCulture:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is less than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

StringComparison.Ordinal:
LATIN SMALL LETTER I (U+0069) is less than LATIN SMALL LETTER DOTLESS I (U+0131)
LATIN SMALL LETTER I (U+0069) is greater than LATIN CAPITAL LETTER I (U+0049)
LATIN SMALL LETTER DOTLESS I (U+0131) is greater than LATIN CAPITAL LETTER I (U+0049)

InvariantCulture'un (U + 0069, U + 0049, U + 00131), Sıradan verimleri (U + 0049, U + 0069, U + 00131) sağladığı yerlerde görebilirsiniz.


25
Normal karşılaştırma baytlara değil, kod noktalarına bakar .
Joey

144
Yararlı bilgi gibi hissediyorum, ama aslında soruya cevap vermiyor. İki dizenin Eşitliğini belirlerken , Ordinal yerine InvarintCulture kullanmak için herhangi bir neden var mı? Görünüşe göre InvariantCulture dizeleri sıralamak için kullanılacak ve Ordinal Eşitlik kontrolü için kullanılmalıdır (aksanlı-a'nın a'dan önce veya sonra gelmesi umrumda değil, sadece farklı). Yine de kendim bu noktadan biraz emin değilim.
MPavlak

18
Bkz msdn.microsoft.com/en-us/library/ms230117%28v=vs.90%29.aspx ve dize normalleştirme ve sıra karşılaştırma önerilir haber.
MPavlak

23
Ordinal çok daha hızlı
Darren

9
Her bir farklı dize karşılaştırma yönteminin performansını ve zamanını gösteren C # Dize Karşılaştırma Testleri yayınlanan iyi performans testi sonuçları vardır .
Kumar C

262

Örneğin, önemli - karakter genişletme denen bir şey var

var s1 = "Strasse";
var s2 = "Straße";

s1.Equals(s2, StringComparison.Ordinal);           //false
s1.Equals(s2, StringComparison.InvariantCulture);  //true

İle InvariantCultureß karakteri ss genişletilmiş olur.


1
Bu şey Ordinalve arasında da farklı InvariantCulturemıdır? Asıl soru bu.
Matthijs Wessels

3
Bilmiyorum olanlar için ßbunu belirtmek gerekir ki ßAlman eşittir en az bir çift s, Kaynak için: en.wikipedia.org/wiki/%C3%9F
Peter

20
@Peter tam olarak doğru değil , Almanca olarak değiştirilemez ßve ssdeğiştirilemez (Ben anadili konuşuyorum ). Her ikisinin de yasal olduğu durumlar vardır (ancak genellikle biri modası geçmiş / önerilmez) ve yalnızca bir forma izin verilen durumlar vardır.
enzi

5
Bu basit örnek, 2 karşılaştırma arasındaki farkı açıkça göstermektedir. Sanırım şimdi anladım.
BrianLegg

4
Denemek zorunda kaldı: ideone.com/j8DvDo çok havalı! Almanca da küçük bir ders. Ss ve ss arasındaki farkın ne olduğunu merak ediyorum ...
Mzn

111

.NET Framework'te Dizeleri Kullanmak için En İyi Uygulamalara İşaret Etme :

  • Kültür-agnostik dize eşleşmesi için güvenli varsayılanınız olarak StringComparison.Ordinalveya StringComparison.OrdinalIgnoreCasekarşılaştırmaları kullanın .
  • Daha iyi performans için StringComparison.Ordinalveya ile karşılaştırmalar kullanın StringComparison.OrdinalIgnoreCase.
  • Karşılaştırmanın dilsel olarak alakasız olduğu zamana (örneğin sembolik) göre dize işlemleri yerine dilbilimsel olmayan StringComparison.Ordinalveya StringComparison.OrdinalIgnoreCasedeğerleri kullanın CultureInfo.InvariantCulture.

Ve sonunda:

  • StringComparison.InvariantCultureÇoğu durumda dize işlemlerini kullanmayın . Birkaç istisnadan biri, dilsel olarak anlamlı ancak kültürel olarak agnostik verilere devam ettiğinizdir.

56

Bir başka kullanışlı fark (aksanların nadir olduğu İngilizce), bir InvariantCulture karşılaştırmasının tüm dizeleri büyük / küçük harf duyarsız olarak karşılaştırması ve daha sonra gerekirse (ve talep edilmesi durumunda) ilk önce yalnızca farklı harfleri karşılaştırdıktan sonra duruma göre ayırt edilmesidir. (Elbette, büyük / küçük harfe göre ayırt edilmeyen büyük / küçük harfe duyarlı olmayan bir karşılaştırma da yapabilirsiniz.) Düzeltildi:Aksanlı harfler aynı harflerin başka bir lezzeti olarak kabul edilir ve dize ilk önce aksanları görmezden gelir ve sonra genel harflerin eşleşip eşleşmediğini hesaplar (büyük / küçük harf duyarsız bir karşılaştırmada nihayetinde göz ardı edilmezse, farklı durumlar için olduğu kadar). Bu, ilk aksan farkında tamamen ayrı olmak yerine, aksi takdirde aynı kelimenin sürümlerini birbirine yakın şekilde vurguladı. Bu, genellikle sözlükte bulacağınız sıralama düzenidir, büyük harfli kelimeler küçük harf eşdeğerlerinin hemen yanında görünür ve aksanlı harfler karşılık gelen vurgusuz harfe yakındır.

Bir sıralı karşılaştırma, ilk farkta durarak, kesinlikle sayısal karakter değerlerini karşılaştırır. Bu, büyük harfleri küçük harflerden tamamen ayrı olarak sıralar (ve büyük olasılıkla bunlardan ayrı olan aksanlı harfler), bu nedenle büyük harfli kelimeler küçük harf eşdeğerlerinin yakınında hiçbir yerde sıralanmaz.

InvariantCulture ayrıca büyük harflerin küçük harflerden daha büyük olduğunu düşünürken, Ordinal büyük harflerin küçük harflerden daha küçük olduğunu düşünür (bilgisayarların küçük harflere sahip olmasından önceki eski günlerden itibaren ASCII'nin devredilmesi, önce büyük harflerin ayrılması ve dolayısıyla küçük harflerden daha düşük değerlerin olması daha sonra eklendi).

Örneğin, Ordinal tarafından: "0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"

Ve InvariantCulture tarafından: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"


Buna bir kez daha baktım ve InvariantCulture örneği ile aksanlı karakterlerin kullanımı hakkındaki açıklamam arasında bir tutarsızlık olduğunu fark ettim. Örnek doğru görünüyor, bu yüzden açıklamanın tutarlı olmasını düzelttim. InvariantCulture karşılaştırması ilk fark vurgusunda durmaz ve aynı harf üzerindeki aksan farkını yalnızca aksanların ve vakaların yanı sıra eşleşiyorsa görünür. Vurgu farkı, daha önceki bir vaka farkından önce dikkate alınır, bu nedenle "Aaba" <"aába".
Rob Parker

31

Her ne kadar soru eşitlikle ilgili olsa da , hızlı görsel referans için, burada bazı dizelerin sırası, bazı dışa vurumların bazılarını gösteren birkaç kültür kullanılarak sıralanmıştır .

Ordinal          0 9 A Ab a aB aa ab ss Ä Äb ß ä äb      
IgnoreCase       0 9 a A aa ab Ab aB ss ä Ä äb Äb ß      
--------------------------------------------------------------------
InvariantCulture 0 9 a A  ä Ä aa ab aB Ab äb Äb ss ß     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ß ss     
--------------------------------------------------------------------
da-DK            0 9 a A  ab aB Ab ss ß ä Ä äb Äb aa     
IgnoreCase       0 9 A a  Ab aB ab ß ss Ä ä Äb äb aa     
--------------------------------------------------------------------
de-DE            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
en-US            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     
--------------------------------------------------------------------
ja-JP            0 9 a A  ä Ä aa ab aB Ab äb Äb ß ss     
IgnoreCase       0 9 A a  Ä ä aa Ab aB ab Äb äb ss ß     

Gözlemler:

  • de-DE,, ja-JPve en-USaynı şekilde sırala
  • InvariantSadece sıralar ssve ßfarklı yukarıdaki üç kültürlerinden
  • da-DK oldukça farklı sıralar
  • IgnoreCaseTüm örnekleme kültürler için uygun maddeler

Yukarıdaki tabloyu oluşturmak için kullanılan kod:

var l = new List<string>
    { "0", "9", "A", "Ab", "a", "aB", "aa", "ab", "ss", "ß",
      "Ä", "Äb", "ä", "äb", "あ", "ぁ", "ア", "ァ", "A", "亜" };

foreach (var comparer in new[]
{
    StringComparer.Ordinal,
    StringComparer.OrdinalIgnoreCase,
    StringComparer.InvariantCulture,
    StringComparer.InvariantCultureIgnoreCase,
    StringComparer.Create(new CultureInfo("da-DK"), false),
    StringComparer.Create(new CultureInfo("da-DK"), true),
    StringComparer.Create(new CultureInfo("de-DE"), false),
    StringComparer.Create(new CultureInfo("de-DE"), true),
    StringComparer.Create(new CultureInfo("en-US"), false),
    StringComparer.Create(new CultureInfo("en-US"), true),
    StringComparer.Create(new CultureInfo("ja-JP"), false),
    StringComparer.Create(new CultureInfo("ja-JP"), true),
})
{
    l.Sort(comparer);
    Console.WriteLine(string.Join(" ", l));
}

1
Hmmm - Tamam, bu araştırmayı yaptığınız ve bulgularınızı yayınladığınız güzel, ancak ne demek istediğinizi tam olarak bilmiyorum. Her neyse, Danimarkalı "en önemli kültürlerden" biri olmayabilir (5 milyon Danimarkalı aslında kendi kültürlerine düşkün olsa da), ancak ek test dizesi olarak "aa" ve "da-DK" ek bir test kültürü, bazı ilginç sonuçlar göreceksiniz.
RenniePet

1
@RenniePet Bunun için teşekkürler. Danimarkaca ekledim, çünkü kullanılan diğer 3 kültürden oldukça farklı. (Ironiyi belirten ifadeler, İngilizce okuma ağında sanıldığım kadar iyi anlaşılmamış gibi göründüğü için, "en önemli kültürler" yorumunu kaldırdım. Sonuçta BCL, CultureComparerkullanabileceğimiz bir özellik içermiyor Bu tablo için Danishkültürün (bilgi) çok önemli olduğu ortaya çıktı.)
Eugene Beresovsky

1
Teşekkürler. "En önemli kültürler" yorumunuzun bir tuz tanesi ile alınması amaçlandığını fark ettim - sadece ifadeleri kullanamayacak kadar yaşlandım. Mesajlaşmanın o kadar yaygın hale geldiğini anlıyorum ki, ifadeleri kullanmak, kimsenin gülüp gülmediğine bakılmaksızın, şakalarınızı onlara anlattıktan sonra açıklamak gibidir. Bu arada, diğer İskandinav kültürleri (Fince, Norveççe ve İsveççe), Danca'nın elbette üstün bir kültür olduğunu kanıtlayan "aa" nın çok özel kullanımı dışında Danimarkaca ile aynıdır.
RenniePet

1
Değer için Danimarka dili ä ve aa'yı alfabenin sonunda yazılı sırayla æ (ae), ø (oe, ö) ve å (aa, ä) özel harflerinin konumu nedeniyle farklı şekilde sıralar.
Alrekr


5

InvariantCultureIgnoreCase ve OrdinalIgnoreCase kullanarak dize eşitliği karşılaştırmasının aynı sonuçları vermeyeceği bir örnek:

string str = "\xC4"; //A with umlaut, Ä
string A = str.Normalize(NormalizationForm.FormC);
//Length is 1, this will contain the single A with umlaut character (Ä)
string B = str.Normalize(NormalizationForm.FormD);
//Length is 2, this will contain an uppercase A followed by an umlaut combining character
bool equals1 = A.Equals(B, StringComparison.OrdinalIgnoreCase);
bool equals2 = A.Equals(B, StringComparison.InvariantCultureIgnoreCase);

Bunu çalıştırırsanız, equals1 yanlış ve equals2 doğru olacaktır.


Sadece başka bir benzer örnek eklemek için, ancak dize değişmez değerleri ile, a="\x00e9"(e akut) ve b="\x0065\x0301"(e akut vurgu ile birleştiğinde), StringComparer.Ordinal.Equals(a, b)false StringComparer.InvariantCulture.Equals(a, b)döndürürken true döndürür.
George Helyar

2

Farkı göstermek için süslü unicode char exmaples kullanmaya gerek yok. İşte bugün bulduğum, sadece ASCII karakterlerinden oluşan şaşırtıcı bir örnek.

ASCII tablosuna göre sıralı olarak karşılaştırıldığında (0x48) (0x95) 0değerinden daha küçüktür _. InvariantCulture bunun tersini söyler (aşağıdaki PowerShell kodu):

PS> [System.StringComparer]::Ordinal.Compare("_", "0")
47
PS> [System.StringComparer]::InvariantCulture.Compare("_", "0")
-1

-7

InvariantCulture'u her zaman aşırı yük olarak kabul eden dize yöntemlerinde kullanmaya çalışın. InvariantCulture kullanarak güvenli bir taraftasınız. Birçok .NET programcısı bu işlevi kullanamayabilir, ancak yazılımınız farklı kültürler tarafından kullanılacaksa, InvariantCulture son derece kullanışlı bir özelliktir.


3
Yazılımınız farklı kültürler tarafından kullanılmayacaksa, Ordinal'den çok daha yavaştır.
Kyle

4
Aşağı oylamayı düşündüm çünkü gelişigüzel cevabınızı kesinlikle düşünmediniz. İçinde olmasına rağmen bir gerçeklik tanesidir. Eğer uygulamanız birden fazla kültür arasında kitlesel yayılmışsa ... Bu kesinlikle "Her zaman InvariantCulture'u kullanmaya çalışın" sözlerini garanti etmez, değil mi? Bir aşağı oy ve belki de daha fazla deneyim aldıktan sonra bu çılgınlığı düzenlemek için yıllar boyunca geri gelmediğinize şaşırdım.
Suamere
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.