Którego generalnie najlepiej użyć - StringComparison.OrdinalIgnoreCase czy StringComparison.InvariantCultureIgnoreCase?

161

Mam taki kod:

If key.Equals("search", StringComparison.OrdinalIgnoreCase) Then
    DoSomething()
End If

Nie obchodzi mnie sprawa. Powinno się używać OrdinalIgnoreCase, InvariantCultureIgnoreCaselub CurrentCultureIgnoreCase?

Dave Haynes
źródło
2
Sprawdź, czy to naprawdę przydatne w tym wątku. Moja sugestia, aby użyć do porównania ordianlignorecase. blogs.msdn.com/b/noahc/archive/2007/06/29/…
UmaMaheswaran
Rozważ otrzymaną odpowiedź z podwójnego porównania ciągów: InvariantCultureIgnoreCase vs OrdinalIgnoreCase?
Michael Freidgeim
Ogólnie rzecz biorąc, zależy to w dużej mierze od tego, jakie rzeczy porównujesz. W szczególności, jeśli jest to zależne od kultury dane wejściowe użytkownika lub elementy wewnętrzne. Nie chcesz, aby kultura komputera zepsuła porównanie wewnętrznego ciągu kodu.
Nyerguds

Odpowiedzi:

179

Nowsze dokumenty .Net mają teraz tabelę, która pomoże Ci zdecydować, która z nich jest najlepsza w Twojej sytuacji.

Z „ nowych zaleceń dotyczących używania ciągów znaków w Microsoft .NET 2.0 ” MSDN

Podsumowanie: Właściciele kodu, którzy poprzednio używali InvariantCulturedo porównywania ciągów, wielkości liter i sortowania, powinni zdecydowanie rozważyć użycie nowego zestawu Stringprzeciążeń w Microsoft .NET 2.0. W szczególności, dane, które są zaprojektowane, aby być kulturowo i językowo nieistotny agnostykiem powinny rozpocząć podając przeciążeń przy użyciu albo StringComparison.Ordinalczy StringComparison.OrdinalIgnoreCaseczłonkowie nowego StringComparisonwyliczenia. Wymuszają one porównywanie bajt po bajcie, podobne do strcmptego, które nie tylko zapobiega błędom wynikającym z językowej interpretacji zasadniczo symbolicznych ciągów, ale zapewnia lepszą wydajność.

Robert Taylor
źródło
126
Aby podać przykład, w którym się różnią, rozważ dwa ciągi "Straße"i "STRASSE". Podczas korzystania z OrdinalIgnoreCasetych Equalszwrotów false, podczas gdy InvariantCultureIgnoreCasemówi, że są równe.
Jeppe Stig Nielsen
2
Zaktualizowany link: docs.microsoft.com/en-us/dotnet/standard/base-types/…
Ohad Schneider
64

To wszystko zależy

Porównanie ciągów znaków Unicode jest trudne:

Implementacja wyszukiwania ciągów znaków Unicode i porównań w oprogramowaniu do przetwarzania tekstu musi uwzględniać obecność równoważnych punktów kodowych. W przypadku braku tej funkcji użytkownicy szukający określonej sekwencji punktów kodowych nie byliby w stanie znaleźć innych wizualnie nierozróżnialnych glifów, które mają inną, ale kanonicznie równoważną reprezentację punktu kodowego.

patrz: http://en.wikipedia.org/wiki/Unicode_equivalence


Jeśli próbujesz porównać 2 ciągi znaków Unicode w sposób niewrażliwy na wielkość liter i chcesz, aby działały WSZĘDZIE , masz niemożliwy do rozwiązania problem.

Klasycznym przykładem jest tureckie i , które, gdy jest duże, zmienia się w İ (zwróć uwagę na kropkę)

Domyślnie .Net framework zwykle używa CurrentCulture do funkcji związanych z ciągami, z bardzo ważnym wyjątkiem, .Equalsże używa porównania porządkowego (bajt po bajcie).

Z założenia prowadzi to do tego, że różne funkcje łańcuchowe zachowują się różnie w zależności od kultury komputera.


Niemniej jednak czasami potrzebujemy porównania „ogólnego przeznaczenia”, bez uwzględniania wielkości liter.

Na przykład możesz chcieć, aby porównanie ciągów zachowywało się w ten sam sposób, niezależnie od komputera, na którym jest zainstalowana Twoja aplikacja.

Aby to osiągnąć, mamy 3 opcje:

  1. Ustaw kulturę jawnie i wykonaj porównanie bez uwzględniania wielkości liter przy użyciu reguł równoważności Unicode.
  2. Ustaw kulturę na niezmienną kulturę i wykonaj porównanie bez rozróżniania wielkości liter przy użyciu reguł równoważności Unicode.
  3. Użyj OrdinalIgnoreCase, która spowoduje wielkie litery w ciągu przy użyciu InvariantCulture, a następnie wykonaj porównanie bajt po bajcie.

Reguły równoważności Unicode są skomplikowane, co oznacza, że ​​użycie metody 1) lub 2) jest droższe niż OrdinalIgnoreCase. Fakt, że OrdinalIgnoreCasenie wykonuje żadnej specjalnej normalizacji Unicode, oznacza, że ​​niektóre ciągi, które renderują się w ten sam sposób na ekranie komputera, nie będą uważane za identyczne. Na przykład: "\u0061\u030a"i "\u00e5"oba renderują å. Jednak w porównaniu porządkowym zostanie uznany za inny.

To, który wybierzesz, zależy w dużej mierze od budowanej aplikacji.

  • Gdybym pisał aplikację biznesową, z której korzystali tylko tureccy użytkownicy, z pewnością użyłbym metody 1.
  • Gdybym tylko potrzebował prostego "fałszywego" porównania bez rozróżniania wielkości liter, na przykład nazwy kolumny w bazie danych, która jest zwykle angielska, prawdopodobnie użyłbym metody 3.

Firma Microsoft ma swój zestaw zaleceń z wyraźnymi wskazówkami. Jednak naprawdę ważne jest, aby zrozumieć pojęcie równoważności Unicode przed przystąpieniem do tych problemów.

Należy również pamiętać, że OrdinalIgnoreCase to bardzo szczególny rodzaj bestii, czyli wybieranie i wybieranie odrobiny porównania porządkowego z kilkoma mieszanymi aspektami leksykograficznymi. To może być mylące.

Sam Saffron
źródło
A jeśli tworzę turecką aplikację, która będzie używana tylko przez tureckich użytkowników, ale chcę, aby „ayakkabı” i „ayakkabi” były równe, czy jest sposób? Kiedy ludzie piszą na swoich telefonach, większość z nich domyślnie używa angielskiej klawiatury i nie obchodzi ich, czy wpiszą „ı” czy „i”.
Volkan Sen
4

Myślę, że to zależy od twojej sytuacji. Ponieważ porównania porządkowe w rzeczywistości dotyczą liczbowych wartości Unicode znaków, nie będą one najlepszym wyborem podczas sortowania alfabetycznego. Jednak w przypadku porównań ciągów liczba porządkowa byłaby odrobinę szybsza.

Bullines
źródło
1

To zależy od tego, co chcesz, ale ja unikają InvariantCulture chyba że jesteś bardzo pewny, że nigdy nie będziesz chciał zlokalizować kod dla innych języków. Zamiast tego użyj CurrentCulture.

Ponadto OrdinalIgnoreCase powinien respektować liczby, które mogą, ale nie muszą, być tym, czego chcesz.

Joel Coehoorn
źródło
1
Napisałeś kiedyś kod VB6 w środowisku mieszanym? Możesz utworzyć kod, który kompiluje się na komputerze z francuskimi ustawieniami narodowymi, ale nie będzie kompilował się na komputerach z angielskimi ustawieniami narodowymi, ponieważ wszystkie liczby przechowywane w zasobach formularza używają formatu bieżącej lokalizacji. Twierdzę, że musisz przyjąć odwrotne podejście: bądź bardzo ostrożny, kiedy używasz obecnej kultury. Zawsze myśl o tym, czy Twój system będzie nadal działał, gdy jego dane będą przenoszone między kulturami. To samo dotyczy stref czasowych.
Wim Coenen
Zgadzam się z odpowiedzią „to zależy”. chociaż nie podążasz za bitem „szanuj liczby”?
Sam Saffron
-1

Bardzo prosta odpowiedź brzmi: jeśli nie używasz języka tureckiego, nie musisz używać InvariantCulture.

Zobacz poniższy link:

Jaka jest różnica między ToUpper () a ToUpperInvariant () w języku C #?

TheMoot
źródło
5
Ta odpowiedź może być prosta, ale jest też bardzo błędna. Tureckie „ja” to tylko przykład , możliwych pułapek jest znacznie więcej.
Ohad Schneider
Które więcej pułapek? Po prostu wiem o tureckim problemie.
HelloWorld
Tak, oprócz tureckiego jest też Azeri. Ale to jest to.
Jim Balter,