224

Which would be better code:

int index = fileName.LastIndexOf(".", StringComparison.InvariantCultureIgnoreCase);

or

int index = fileName.LastIndexOf(".", StringComparison.OrdinalIgnoreCase);
RichardTowers
  • 4,682
  • 1
  • 26
  • 43
JL.
  • 78,954
  • 126
  • 311
  • 459
  • 12
    that would depend on what you are trying to achieve... – Mitch Wheat May 01 '10 at 11:03
  • 4
    @MartinLiversage marking c# question as duplicate of vb.net question.. funny at least. Believe both should share .Net tag in this case – Lanorkin Aug 28 '17 at 05:29
  • 1
    @Lanorkin: The distinction between the two enum values are the same in VB.NET and C# and none of the answers to both this question and the other are specific to either VB.NET or C#. The two questions are clearly duplicates and by associating them as I have done it becomes easier to find the relevant information about these enum values. – Martin Liversage Aug 28 '17 at 08:24
  • 1
    @MartinLiversage exactly that's why I use word "funny" – Lanorkin Aug 28 '17 at 08:29
  • I don't think this is a duplicate question because this question is asking about file name parsing and the other question seems to be asking about user input. File name parsing has different requirements. I wish the title started off with "String comparison of file names: ...", then this question would be clearer. – Ron Feb 06 '19 at 20:08

4 Answers4

307

Neither code is always better. They do different things, so they are good at different things.

InvariantCultureIgnoreCase uses comparison rules based on english, but without any regional variations. This is good for a neutral comparison that still takes into account some linguistic aspects.

OrdinalIgnoreCase compares the character codes without cultural aspects. This is good for exact comparisons, like login names, but not for sorting strings with unusual characters like é or ö. This is also faster because there are no extra rules to apply before comparing.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 8
    how does `InvariantCultureIgnoreCase ` behave when he meet `ä` ? as oppose to `OrdinalIgnoreCase ` ...? – Royi Namir Nov 08 '12 at 14:28
  • 1
    @RoyiNamir: The invariant culture is based on english, so it would treat `ä`, `à`, `å`, et.c. as `a`, i.e. remove diacritics. Using an ordinal culture would place the characters with diacritics after all the regular letters, i.e. sorted strictly on character code. – Guffa Nov 08 '12 at 15:45
  • you mean that they all will be uppercase A (InvariantCultureIgnoreCase ) right ? – Royi Namir Nov 08 '12 at 15:52
  • but also OrdinalIgnoreCase compares the character codes without cultural aspects......so ? – Royi Namir Nov 08 '12 at 15:59
  • 25
    @RoyiNamir: Yes, the case will be ignored when they are compared. `OrdinalIgnoreCase` makes a case conversion, but then it compares on the character code, so `à` and `À` are equal, but `A` and `À` are different. – Guffa Nov 08 '12 at 18:30
  • 8
    according to your first comment to me : why this code `string s1 = "hello";string s2 = "héllo"; s1.Equals(s2, StringComparison.InvariantCulture)` return False ? you said that a and à is treated the same... – Royi Namir Jan 11 '13 at 18:01
  • 11
    @RoyiNamir: Yes, you are right, the characters are not treated as strictly equal, but when you sort strings the `é` will be right after `e`, not somewhere after `z`. – Guffa Jan 11 '13 at 18:16
  • so it is for sorting and not for equalizing ? – Royi Namir Jan 11 '13 at 18:17
  • 14
    @RoyiNamir: Yes, for that character it works that way, other characters may actually be evaluated as equal, or a character may be equal to two other characters. The strings `"lasst"` and `"laßt"` are actually equal. – Guffa Jan 11 '13 at 18:34
  • 1
    This is one explanation that really helped me understand.. – nawfal Jun 06 '13 at 05:49
  • 2
    @Guffa Strictly speaking, it is a bad idea to do case insensitive comparison for passwords. Password comparison should use `Ordinal`, not `OrdinalIgnoreCase` – Svein Fidjestøl Jul 15 '15 at 12:03
  • 1
    @SveinFidjestøl: Good point. I used a different example in the answer. – Guffa Jul 15 '15 at 14:48
  • hi thank you for your answer Mr @Guffa - could you elaborate more on what you mean by: "takes into account some linguistic aspects"? – BenKoshy Feb 21 '17 at 21:55
  • Beware of OrdinalIgnoreCase when you compare human-readable strings at all, the letters I and i are different letters in Turkish locale! – Michael Yutsis Feb 07 '18 at 09:08
64

FXCop typically prefers OrdinalIgnoreCase. But your requirements may vary.

For English there is very little difference. It is when you wander into languages that have different written language constructs that this becomes an issue. I am not experienced enough to give you more than that.

OrdinalIgnoreCase

The StringComparer returned by the OrdinalIgnoreCase property treats the characters in the strings to compare as if they were converted to uppercase using the conventions of the invariant culture, and then performs a simple byte comparison that is independent of language. This is most appropriate when comparing strings that are generated programmatically or when comparing case-insensitive resources such as paths and filenames. http://msdn.microsoft.com/en-us/library/system.stringcomparer.ordinalignorecase.aspx

InvariantCultureIgnoreCase

The StringComparer returned by the InvariantCultureIgnoreCase property compares strings in a linguistically relevant manner that ignores case, but it is not suitable for display in any particular culture. Its major application is to order strings in a way that will be identical across cultures. http://msdn.microsoft.com/en-us/library/system.stringcomparer.invariantcultureignorecase.aspx

The invariant culture is the CultureInfo object returned by the InvariantCulture property.

The InvariantCultureIgnoreCase property actually returns an instance of an anonymous class derived from the StringComparer class.

Clément
  • 12,299
  • 15
  • 75
  • 115
Sky Sanders
  • 36,396
  • 8
  • 69
  • 90
54

If you really want to match only the dot, then StringComparison.Ordinal would be fastest, as there is no case-difference.

"Ordinal" doesn't use culture and/or casing rules that are not applicable anyway on a symbol like a ..

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
18

You seem to be doing file name comparisons, so I would just add that OrdinalIgnoreCase is closest to what NTFS does (it's not exactly the same, but it's closer than InvariantCultureIgnoreCase)

Dean Harding
  • 71,468
  • 13
  • 145
  • 180