Perbedaan antara InvariantCulture dan perbandingan string Ordinal

548

Ketika membandingkan dua string dalam c # untuk kesetaraan, apa perbedaan antara InvariantCulture dan perbandingan Ordinal?

Kapil
sumber
Mungkin siao2.com/2004/12/29/344136.aspx ? (googled)
Keju Daneish
2
Bagi mereka yang menggunakan String1.Equals(String2, StringComparison.Ordinal), Anda lebih baik menggunakan String1 == String2yang secara intrinsik String1.Equals(String2)dan itu secara default perbandingan peka huruf besar-kecil.
Ghasan
3
@Ghasan Tidak yakin apakah itu membuat =="lebih baik", tetapi itu adalah a) lebih pendek, b) kurang eksplisit tentang apa tepatnya yang dilakukannya dan c) String1dapat menjadi nol tanpa perbandingan melempar a NullReferenceException.
Eugene Beresovsky
3
@Ghasan Praktik Terbaik MSDN resmi untuk Menggunakan String di halaman .NET Framework ( msdn.microsoft.com/en-us/library/… ) merekomendasikan penggunaan kelebihan beban yang secara eksplisit menentukan StringComparisonjenisnya. Dalam kasus perbandingan string, artinya String.Equals.
Ohad Schneider
3
@EugeneBeresovsky Untuk menghindari NullReferenceExceptionAnda hanya dapat menggunakan metode statis: String.Equals(string1, string2, StringComparison.Ordinal).
Ohad Schneider

Jawaban:

302

Budaya Invariant

Menggunakan seperangkat urutan karakter "standar" (a, b, c, ... dll). Ini berbeda dengan beberapa lokal tertentu, yang dapat mengurutkan karakter dalam urutan yang berbeda ('a-dengan-akut' mungkin sebelum atau setelah 'a', tergantung pada lokal, dan sebagainya).

Urut

Di sisi lain, terlihat murni pada nilai byte mentah yang mewakili karakter.


Ada contoh yang bagus di http://msdn.microsoft.com/en-us/library/e6883c06.aspx yang menunjukkan hasil dari berbagai nilai StringComparison. Sepanjang jalan, itu menunjukkan (dikutip):

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)

Anda dapat melihat bahwa di mana InvariantCulture menghasilkan (U + 0069, U + 0049, U + 00131), hasil ordinal (U + 0049, U + 0069, U + 00131).

JaredReisinger
sumber
25
Perbandingan ordinal terlihat pada poin kode , bukan byte.
Joey
144
Saya merasa seperti informasi yang berguna, tetapi sebenarnya tidak menjawab pertanyaan. Saat menentukan Kesetaraan dua string, apakah ada alasan untuk menggunakan InvarintCulture alih-alih Ordinal? Tampaknya InvariantCulture akan digunakan untuk Mengurutkan string, dan Ordinal harus digunakan untuk pemeriksaan Kesetaraan (kami tidak peduli bahwa aksen-a datang sebelum atau setelah a, itu hanya berbeda). Padahal, saya sendiri agak tidak yakin dengan hal ini.
MPavlak
18
Lihat msdn.microsoft.com/en-us/library/ms230117%28v=vs.90%29.aspx dan perhatikan bahwa normalisasi string dan perbandingan ordinal direkomendasikan.
MPavlak
23
Ordinal jauh lebih cepat
Darren
9
Ada hasil tes kinerja yang baik yang dipublikasikan C # String Comparision Tests yang menceritakan kinerja masing-masing metode perbandingan string dan waktu mereka.
Kumar C
262

Itu penting, misalnya - ada hal yang disebut ekspansi karakter

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

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

Dengan InvariantCulturekarakter ß diperluas ke ss.

Ventsyslav Raikov
sumber
1
Apakah hal ini juga berbeda dalam beberapa hal antara Ordinaldan InvariantCulture? Itulah pertanyaan aslinya.
Matthijs Wessels
3
Bagi mereka yang tidak tahu ßharus dicatat bahwa ßsetidaknya dalam bahasa Jerman sama dengan double s, Sumber: en.wikipedia.org/wiki/%C3%9F
Peter
20
@Peter tidak sepenuhnya benar, Anda tidak dapat menggunakan ßdan secara ssbergantian dalam bahasa Jerman (saya seorang penutur asli). Ada kasus-kasus di mana keduanya legal (tetapi seringkali salah satu sudah usang / tidak direkomendasikan) dan ada kasus di mana hanya satu formulir yang diizinkan.
enzi
5
Contoh sederhana ini dengan jelas menunjukkan perbedaan antara 2 perbandingan. Saya pikir saya mendapatkan ini sekarang.
BrianLegg
4
Harus mencobanya: ideone.com/j8DvDo begitu keren! Sedikit pelajaran dalam bahasa Jerman juga. Ingin tahu apa perbedaan antara ß dan ss sekarang ...
Mzn
111

Menunjuk ke Praktik Terbaik untuk Menggunakan String di .NET Framework :

  • Gunakan StringComparison.Ordinalatau StringComparison.OrdinalIgnoreCaseuntuk perbandingan sebagai standar aman Anda untuk pencocokan string agnostik kultur.
  • Gunakan perbandingan dengan StringComparison.Ordinalatau StringComparison.OrdinalIgnoreCaseuntuk kinerja yang lebih baik.
  • Gunakan nilai-nilai non-linguistik StringComparison.Ordinalatau StringComparison.OrdinalIgnoreCasebukannya operasi string yang didasarkan pada CultureInfo.InvariantCultureketika perbandingan tidak relevan secara linguistik (simbolis, misalnya).

Dan akhirnya:

  • Jangan gunakan operasi string berdasarkan pada StringComparison.InvariantCulturekebanyakan kasus . Salah satu dari sedikit pengecualian adalah ketika Anda mempertahankan data agnostik yang secara linguistik bermakna tetapi secara budaya.
Dariusz
sumber
56

Perbedaan praktis lainnya (dalam bahasa Inggris di mana aksen tidak umum) adalah bahwa perbandingan InvariantCulture membandingkan seluruh string dengan case-insensitive pertama, dan kemudian jika perlu (dan diminta) membedakan dengan case setelah terlebih dahulu membandingkan hanya pada huruf yang berbeda. (Anda juga dapat melakukan perbandingan case-insensitive, tentu saja, yang tidak akan membedakan dengan case.) Dikoreksi:Huruf beraksen dianggap sebagai citarasa lain dari huruf-huruf yang sama dan string dibandingkan pertama kali mengabaikan aksen dan kemudian memperhitungkannya jika huruf-huruf umum semuanya cocok (seperti halnya case yang berbeda kecuali pada akhirnya tidak diabaikan dalam perbandingan case-insensitive). Grup-grup ini mengaksen versi-versi kata yang sebaliknya dekat satu sama lain, bukannya sepenuhnya terpisah pada perbedaan aksen pertama. Ini adalah urutan yang biasanya Anda temukan dalam kamus, dengan kata-kata berhuruf besar muncul tepat di sebelah padanan huruf kecilnya, dan huruf beraksen berada di dekat huruf yang tidak beraksen.

Perbandingan ordinal membandingkan secara ketat pada nilai karakter numerik, berhenti pada perbedaan pertama. Jenis huruf besar ini benar-benar terpisah dari huruf kecil (dan huruf beraksen agaknya terpisah dari huruf kecil), jadi kata-kata dengan huruf besar tidak akan menyamai tempat yang dekat dengan huruf kecilnya.

InvariantCulture juga menganggap huruf kapital lebih besar daripada huruf kecil, sedangkan Ordinal menganggap huruf kapital lebih kecil dari huruf kecil (peninggalan ASCII dari masa lalu sebelum komputer memiliki huruf kecil, huruf besar dialokasikan terlebih dahulu dan dengan demikian memiliki nilai lebih rendah dari huruf kecil ditambahkan nanti).

Misalnya, menurut Ordinal: "0" < "9" < "A" < "Ab" < "Z" < "a" < "aB" < "ab" < "z" < "Á" < "Áb" < "á" < "áb"

Dan oleh InvariantCulture: "0" < "9" < "a" < "A" < "á" < "Á" < "ab" < "aB" < "Ab" < "áb" < "Áb" < "z" < "Z"

Rob Parker
sumber
Saya melihat lagi hal ini dan melihat ada ketidakkonsistenan antara contoh InvariantCulture dan penjelasan saya tentang penanganan karakter beraksen. Contohnya tampaknya benar, jadi saya sudah mengoreksi penjelasan agar konsisten. Perbandingan InvariantCulture tidak berhenti pada aksen yang berbeda pertama dan tampaknya hanya mempertimbangkan perbedaan aksen pada huruf yang sama jika sisa string cocok dengan aksen dan huruf. Perbedaan aksen kemudian dipertimbangkan sebelum perbedaan huruf sebelumnya, jadi "Aaba" <"aába".
Rob Parker
31

Meskipun pertanyaannya adalah tentang kesetaraan , untuk referensi visual cepat, di sini urutan beberapa string diurutkan menggunakan beberapa budaya yang menggambarkan beberapa keanehan di luar sana.

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 ß     

Pengamatan:

  • de-DE,, ja-JPdan en-USurutkan dengan cara yang sama
  • Invarianthanya macam ssdan ßberbeda dari tiga budaya di atas
  • da-DK agak berbeda
  • yang IgnoreCasehal bendera untuk semua budaya sampel

Kode yang digunakan untuk menghasilkan tabel di atas:

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));
}
Eugene Beresovsky
sumber
1
Hmmm - OK, senang Anda melakukan penelitian ini, dan memposting temuan Anda, meskipun saya tidak yakin apa maksud Anda. Lagi pula, Denmark mungkin bukan salah satu "budaya paling penting" (meskipun 5 juta orang Denmark sebenarnya agak menyukai budaya mereka), tetapi jika Anda melempar "aa" sebagai tes tambahan, dan "da-DK" sebagai budaya tes tambahan, Anda akan melihat beberapa hasil menarik.
RenniePet
1
@RenniePet Terima kasih untuk itu. Saya menambahkan bahasa Denmark, karena agak berbeda dari 3 budaya lain yang digunakan. (Seperti emotikon yang menunjukkan ironi tampaknya tidak terlalu dipahami di web membaca bahasa Inggris seperti yang saya perkirakan, saya menghapus komentar "budaya yang paling penting". Lagi pula, BCL tidak menampilkan fitur CultureCompareryang dapat kita gunakan untuk memverifikasi. Untuk tabel ini, Danishbudaya (info) ternyata sangat penting.)
Eugene Beresovsky
1
Terima kasih. Saya menyadari bahwa komentar "budaya paling penting" Anda dimaksudkan untuk diambil dengan sebutir garam - hanya saja saya sudah terlalu tua untuk menggunakan emotikon. Saya pikir SMS sudah menjadi sangat umum sehingga menggunakan emotikon adalah seperti menjelaskan lelucon Anda setelah Anda memberi tahu mereka, terlepas dari apakah ada yang tertawa atau tidak. Kebetulan, budaya Skandinavia lainnya (Finlandia, Norwegia dan Swedia) adalah sama dengan Denmark, kecuali untuk penanganan yang sangat khusus "aa" - yang membuktikan bahwa Denmark adalah budaya superior, tentu saja.
RenniePet
1
Untuk apa nilainya, Denmark mengurutkan ä dan aa secara berbeda karena lokasi huruf khusus æ (ae), ø (oe, ö), dan å (aa, ä) pada akhir alfabet dalam urutan tertulis.
Alrekr
5

Berikut adalah contoh di mana perbandingan kesetaraan string menggunakan InvariantCultureIgnoreCase dan OrdinalIgnoreCase tidak akan memberikan hasil yang sama:

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

Jika Anda menjalankan ini, equals1 akan salah, dan equals2 akan benar.

Dwedit
sumber
Hanya untuk menambahkan contoh serupa lainnya tetapi dengan string literal, jika a="\x00e9"(e akut) dan b="\x0065\x0301"(e dikombinasikan dengan aksen akut), StringComparer.Ordinal.Equals(a, b)akan mengembalikan false sementara StringComparer.InvariantCulture.Equals(a, b)akan mengembalikan true.
George Helyar
2

Tidak perlu menggunakan exmaples unicode char yang mewah untuk menunjukkan perbedaannya. Inilah satu contoh sederhana yang saya temukan hari ini yang mengejutkan, hanya terdiri dari karakter ASCII.

Menurut tabel ASCII, 0(0x48) lebih kecil dari _(0x95) bila dibandingkan secara ordinal. InvariantCulture akan mengatakan sebaliknya (kode PowerShell di bawah):

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

Selalu mencoba menggunakan InvariantCulture dalam metode string yang menerimanya sebagai kelebihan beban. Dengan menggunakan InvariantCulture Anda berada di sisi yang aman. Banyak pemrogram .NET mungkin tidak menggunakan fungsi ini tetapi jika perangkat lunak Anda akan digunakan oleh budaya yang berbeda, InvariantCulture adalah fitur yang sangat berguna.

George
sumber
3
Jika perangkat lunak Anda tidak akan digunakan oleh budaya yang berbeda, itu jauh lebih lambat daripada Ordinal sekalipun.
Kyle
4
Saya mempertimbangkan downvoting karena Anda tentu tidak memikirkan tanggapan serampangan Anda. Padahal di dalamnya ada sebutir kebenaran. JIKA aplikasi Anda tersebar luas di antara beberapa budaya ... Itu tentu saja tidak menjamin kata-kata pembuka Anda "Selalu coba gunakan InvariantCulture", bukan? Saya terkejut Anda belum kembali selama bertahun-tahun untuk mengedit kegilaan ini setelah menerima downvote, dan mungkin lebih banyak pengalaman.
Suamere