201

I have some code like this:

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

I don't care about the case. Should I use OrdinalIgnoreCase, InvariantCultureIgnoreCase, or CurrentCultureIgnoreCase?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Dave Haynes
  • 3,633
  • 6
  • 27
  • 23
  • 2
    Check this its really useful for this thread. My suggestion to use ordianlignorecase for comparison. http://blogs.msdn.com/b/noahc/archive/2007/06/29/string-equals-performance-comparison.aspx – UmaMaheswaran Dec 29 '10 at 07:01
  • Consider highly voted answer from the duplicate [String comparison: InvariantCultureIgnoreCase vs OrdinalIgnoreCase?](//stackoverflow.com/a/2749678) – Michael Freidgeim Oct 31 '17 at 21:34
  • Overall, it depends a lot on what kind of thing you're comparing. Specifically, if it's culture-dependent user input or internal stuff. You don't want the PC's culture messing up internal code string compares. – Nyerguds Jan 08 '18 at 08:26

5 Answers5

217

Newer .Net Docs now has a table to help you decide which is best to use in your situation.

From MSDN's "New Recommendations for Using Strings in Microsoft .NET 2.0"

Summary: Code owners previously using the InvariantCulture for string comparison, casing, and sorting should strongly consider using a new set of String overloads in Microsoft .NET 2.0. Specifically, data that is designed to be culture-agnostic and linguistically irrelevant should begin specifying overloads using either the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase members of the new StringComparison enumeration. These enforce a byte-by-byte comparison similar to strcmp that not only avoids bugs from linguistic interpretation of essentially symbolic strings, but provides better performance.

Robert Taylor
  • 2,860
  • 3
  • 21
  • 19
  • 164
    To give an example where they differ, consider the two strings `"Straße"` and `"STRASSE"`. When using `OrdinalIgnoreCase` the `Equals` returns `false`, whereas `InvariantCultureIgnoreCase` says they're equal. – Jeppe Stig Nielsen Jul 24 '13 at 16:37
  • 1
    This is wrong. `string.Equals("Straße", "STRASSE", StringComparison.InvariantCultureIgnoreCase)` returns `false` – wertzui Jul 22 '22 at 12:52
  • @wertzui the comparison returns `true` on my machine, running .NET 6. – Martin Wiboe Aug 30 '22 at 09:22
  • 1
    What culture are you using? On my machine (Win 11, .Net 6.0.8, de-DE culture), I get the `false` for `CurrentCultureIgnoreCase`, `OrdinalIgnoreCase`, `InvariantCultureIgnoreCase`. However `string.Equals("Straße", "STRAẞE", StringComparison.InvariantCultureIgnoreCase).Dump();` and `string.Equals("Straße", "STRAẞE", StringComparison.CurrentCultureIgnoreCase).Dump();` both return `true`. Note that `STRAẞE` is using an uppercase `ẞ` which was standardized in 2008. – wertzui Aug 30 '22 at 09:59
72

It all depends

Comparing unicode strings is hard:

The implementation of Unicode string searches and comparisons in text processing software must take into account the presence of equivalent code points. In the absence of this feature, users searching for a particular code point sequence would be unable to find other visually indistinguishable glyphs that have a different, but canonically equivalent, code point representation.

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


If you are trying to compare 2 unicode strings in a case insensitive way and want it to work EVERYWHERE, you have an impossible problem.

The classic example is the Turkish i, which when uppercased becomes İ (notice the dot)

By default, the .Net framework usually uses the CurrentCulture for string related functions, with a very important exception of .Equals that uses an ordinal (byte by byte) compare.

This leads, by design, to the various string functions behaving differently depending on the computer's culture.


Nonetheless, sometimes we want a "general purpose", case insensitive, comparison.

For example, you may want your string comparison to behave the same way, no matter what computer your application is installed on.

To achieve this we have 3 options:

  1. Set the culture explicitly and perform a case insensitive compare using unicode equivalence rules.
  2. Set the culture to the Invariant Culture and perform case insensitive compare using unicode equivalence rules.
  3. Use OrdinalIgnoreCase which will uppercase the string using the InvariantCulture and then perform a byte by byte comparison.

Unicode equivalence rules are complicated, which means using method 1) or 2) is more expensive than OrdinalIgnoreCase. The fact that OrdinalIgnoreCase does not perform any special unicode normalization, means that some strings that render in the same way on a computer screen, will not be considered identical. For example: "\u0061\u030a" and "\u00e5" both render å. However in a ordinal compare will be considered different.

Which you choose heavily depends on the application you are building.

  • If I was writing a line-of-business app which was only used by Turkish users, I would be sure to use method 1.
  • If I just needed a simple "fake" case insensitive compare, for say a column name in a db, which is usually English I would probably use method 3.

Microsoft has their set of recommendations with explicit guidelines. However, it is really important to understand the notion of unicode equivalence prior to approaching these problems.

Also, please keep in mind that OrdinalIgnoreCase is a very special kind of beast, that is picking and choosing a bit of an ordinal compare with some mixed in lexicographic aspects. This can be confusing.

Community
  • 1
  • 1
Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • What if I'm building a Turkish app that will only be used by Turkish users but I want "ayakkabı" and "ayakkabi" to be equal, is there a way? When people type on their phones, most of them use English keyboard as default and don't care if they type "ı" or "i". – Volkan Sen Jul 22 '20 at 19:32
4

I guess it depends on your situation. Since ordinal comparisons are actually looking at the characters' numeric Unicode values, they won't be the best choice when you're sorting alphabetically. For string comparisons, though, ordinal would be a tad faster.

Bullines
  • 5,626
  • 6
  • 53
  • 93
1

It depends on what you want, though I'd shy away from invariantculture unless you're very sure you'll never want to localize the code for other languages. Use CurrentCulture instead.

Also, OrdinalIgnoreCase should respect numbers, which may or may not be what you want.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • 1
    Ever wrote VB6 code in a mixed-language environment? You can create code that compiles on a PC with the french locale but won't compile on PCs with the english locale, because any numbers stored in the form resources use the format of the current locale. I'd argue you need to take the opposite approach: be very careful when you use the current culture. Always think about whether your system will still work when its data moves between cultures. Same thing with timezones. – Wim Coenen Apr 02 '10 at 15:47
  • I do agree with the "it depends" answer. though not following the "respect numbers" bit? – Sam Saffron Jun 20 '11 at 02:22
-1

The very simple answer is, unless you are using Turkish, you don't need to use InvariantCulture.

See the following link:

In C# what is the difference between ToUpper() and ToUpperInvariant()?

Community
  • 1
  • 1
TheMoot
  • 2,903
  • 4
  • 26
  • 27
  • 7
    This answer may be simple, but it is also very wrong. The Turkish "I" is just an ***example***, there are many more possible pitfalls. – Ohad Schneider May 22 '14 at 11:41
  • Yeah, in addition to Turkish there's Azeri. But that's it. – Jim Balter Mar 20 '17 at 14:38
  • 1
    I mean in reality, is there really any point in solving problems you will NEVER have? The Science side would say yes, but in practicality its a wasted effort for 99.999% of implementations (and that might not be enough 9s) – Morgeth888 Oct 03 '22 at 20:57