264

How can I make the line below case insensitive?

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username == (string)drUser["Username"]) != -1);

I was given some advice earlier today that suggested I use:

x.Username.Equals((string)drUser["Username"], StringComparison.OrdinalIgnoreCase)));

the trouble is I can't get this to work, I've tried the line below, this compiles but returns the wrong results, it returns enrolled users as unenrolled and unenrolled users as enrolled.

drUser["Enrolled"] = 
      (enrolledUsers.FindIndex(x => x.Username.Equals((string)drUser["Username"], 
                                 StringComparison.OrdinalIgnoreCase)));

Can anyone point out the problem?

SteveC
  • 15,808
  • 23
  • 102
  • 173
Jamie
  • 2,657
  • 2
  • 16
  • 3
  • 1
    What data type should `drUser["Enrolled"]` be? It looks like a boolean value, but `FindIndex()` returns the index. If the index of that user is 0, then it will return 0, which may be false. When, in reality is is true. The `Exists()` method may be better in this case. – drharris Jun 25 '10 at 23:03
  • Are you sure there isn't some time of formatting or an extra space in one field that isn't in the other? – joshlrogers Jun 25 '10 at 23:04
  • 2
    I'd suggest using enrolledUsers.Any() instead of FindIndex (and test). – Marc Jun 25 '10 at 23:16

9 Answers9

484

This is not the best practice in .NET framework (4 & +) to check equality

String.Compare(x.Username, (string)drUser["Username"], 
                  StringComparison.OrdinalIgnoreCase) == 0

Use the following instead

String.Equals(x.Username, (string)drUser["Username"], 
                   StringComparison.OrdinalIgnoreCase) 

MSDN recommends:

  • Use an overload of the String.Equals method to test whether two strings are equal.
  • Use the String.Compare and String.CompareTo methods to sort strings, not to check for equality.
Liam
  • 27,717
  • 28
  • 128
  • 190
ocean4dream
  • 5,082
  • 1
  • 15
  • 17
  • 12
    You should use `string.Compare`, not `String.Compare`. – Fred Apr 16 '16 at 19:36
  • 8
    @Fred I agree but can you qualify the reason? – Gusdor May 21 '16 at 16:08
  • @Gusdor see http://stackoverflow.com/questions/32187486/why-is-string-considered-a-simplified-version-of-string and https://stackoverflow.com/questions/7074/in-c-sharp-whats-the-difference-between-string-and-string – Fred May 22 '16 at 12:18
  • 28
    @Fred I was hoping for a technical reason rather than 'because Stylecop says so'. Am I missing something? – Gusdor May 22 '16 at 15:53
  • 13
    no difference string.compare with String.Compare, string synonyms System.String class. and member Compare is an extension method.@Fred @Gusdor – Nuri YILMAZ Jun 20 '16 at 15:58
  • What about checking equality of substrings (case insensitive)? Continue to use `IndexOf`? – Andrew Truckle Jun 27 '16 at 08:42
  • 41
    @Gusdor `string` is better practice than `String` since it is a language keyword. For one, `String` could be something other than `System.String`, whereas `string` cannot be. Also, `string` is more or less guaranteed to exist in C#, whereas `String` is technically part of .NET rather than C#. – Dave Cousineau Aug 13 '17 at 03:02
  • Can someone explain why `string.Equals(a, b, StringComparison.OrdinalIgnoreCase)` is better than `a?.ToLower() == b?.ToLower()`? – Kyle Delaney Apr 03 '18 at 21:42
  • 4
    @KyleDelaney String comparison is not as simple as the "equality" between two strings. For example in English "encyclopaedia" and "encyclopædia" are equivalent, [even though it's not the same string](https://learn.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=netframework-4.7.1#System_StringComparison_OrdinalIgnoreCase). `string.Equals()` allows you to specify cultural details when doing comparison. Also the code is better at stating its intent. – Alternatex Jun 01 '18 at 11:55
  • @Alternatex I am fully aware that `string.Equals()` allows you to specify cultural details, which is why I was asking about the specific case of `StringComparison.OrdinalIgnoreCase`. Wouldn't that return false in your "encyclopædia" example? – Kyle Delaney Jun 01 '18 at 16:38
  • @KyleDelaney Returning false would make sense in OP's case because he's comparing usernames, so `StringComparison.OrdinalIgnoreCase` is a good fit. I don't think the result will differ from the one in your code if that was your question. May be subjective but I think doing string comparison using `string.Equals()` makes more sense in _most_ cases. – Alternatex Jun 04 '18 at 09:18
  • 1
    the fastest is string.equals. Just look at this little test: https://dotnetfiddle.net/wnja7B – Diogo Luis Sep 11 '18 at 15:27
  • 2
    @KyleDelaney Because the second requires copying `a` and `b` to extra memory to hold their lower case version, which could be expensive for large strings, and then iterating a second time over those two new strings. Imagine if `a` and `b` are long uppercase but identical strings. – Arthur Tacca Jan 04 '19 at 18:52
  • @DaveCousineau "Also, string is more or less guaranteed to exist in C#, whereas String is technically part of .NET rather than C#." - if something exists in .NET, it is guaranteed to exist in C#. Your other points are valid, but with primitive types such as `long` and `int`, I find `Int64` and `Int32` much more descriptive, and you can copy/paste the code and it'll work in any .NET language, not just C#. Same for `float` and `double`, `Single` and `Double` are much more intuitive. – David Klempfner Mar 15 '23 at 07:04
40

Please use this for comparison:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);
Broots Waymb
  • 4,713
  • 3
  • 28
  • 51
  • 16
    Just be aware of the advantages and pitfalls of using CurrentCultureIgnoreCase vs. OrdinalIgnoreCase. If you don't need the semantics of culture comparison, save some performance and use ordinal comparison. – ErikE Dec 01 '16 at 23:42
36

You should use static String.Compare function like following

x => String.Compare (x.Username, (string)drUser["Username"],
                     StringComparison.OrdinalIgnoreCase) == 0
Oleg
  • 220,925
  • 34
  • 403
  • 798
  • 7
    No, you should use `String.Equals` instead of `String.Compare`. There's no need to compute which one is greater, just that they are not equal. – ErikE Dec 01 '16 at 23:41
  • @ErikE: I'm wonder, which method you will recommend to use in 6 years more :-) – Oleg Dec 02 '16 at 00:08
  • 4
    I don't wonder! I'm confident I'll recommend using equality when you want equality semantics, and using compare when you want comparison semantics. What's so difficult about that? `IEquatable` and `IComparable` do NOT do the same thing, and you can have classes that implement one but in which it would make NO sense to implement the other. For example, you could order sensor samplings by time without any of them being equal (IComparable). And, you can indicate whether things are equal (IEquatable) but it makes no sense to order them (say, computer serial numbers). – ErikE Dec 02 '16 at 00:17
  • @ErikE: You don't understand my point of view. Old answers corresponds the time of writing. One should not touch old answers. It's true about the most products. The best practice or the best choice from performance point of view can be changed multiple times later. I see no sense to discuss about any old answer. – Oleg Dec 02 '16 at 00:25
  • 28
    My apologies, I took it as a critique on the correctness of my comment. If what you're saying is that you admit your old answer may not be the best one, then great! However, I have to disagree with you about old answers. Old answers that give poor information *should* be commented on, *should* be down-voted, because they are still informing *today's* readers. – ErikE Dec 02 '16 at 00:50
8

You can (although controverse) extend System.String to provide a case insensitive comparison extension method:

public static bool CIEquals(this String a, String b) {
    return a.Equals(b, StringComparison.CurrentCultureIgnoreCase);
}

and use as such:

x.Username.CIEquals((string)drUser["Username"]);

C# allows you to create extension methods that can serve as syntax suggar in your project, quite useful I'd say.

It's not the answer and I know this question is old and solved, I just wanted to add these bits.

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
Felype
  • 3,087
  • 2
  • 25
  • 36
8

Others answer are totally valid here, but somehow it takes some time to type StringComparison.OrdinalIgnoreCase and also using String.Compare.

I've coded simple String extension method, where you could specify if comparison is case sensitive or case senseless with boolean, attaching whole code snippet here:

using System;

/// <summary>
/// String helpers.
/// </summary>
public static class StringExtensions
{
    /// <summary>
    /// Compares two strings, set ignoreCase to true to ignore case comparison ('A' == 'a')
    /// </summary>
    public static bool CompareTo(this string strA, string strB, bool ignoreCase)
    {
        return String.Compare(strA, strB, ignoreCase) == 0;
    }
}

After that whole comparison shortens by 10 characters approximately - compare:

Before using String extension:

String.Compare(testFilename, testToStart,true) != 0

After using String extension:

testFilename.CompareTo(testToStart, true)
TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
  • 3
    I disagree with the naming, compare is a well known function in software dev and you've fundamentally changed what it does. I think you should either return an int like compare or change the name to something else, 'IsEqual' for example. – Fred Dec 13 '18 at 00:42
7

I'd like to write an extension method for EqualsIgnoreCase

public static class StringExtensions
{
    public static bool? EqualsIgnoreCase(this string strA, string strB)
    {
        return strA?.Equals(strB, StringComparison.CurrentCultureIgnoreCase);
    }
}
Ranga
  • 1,191
  • 12
  • 19
3

I think you will find more information in this link:

http://codeidol.com/community/dotnet/controlling-case-sensitivity-when-comparing-two-st/8873/

Use the Compare static method on the String class to compare the two strings. Whether the comparison is case-insensitive is determined by the third parameter of one of its overloads. For example:

string lowerCase = "abc";
string upperCase = "AbC";
int caseInsensitiveResult = string.Compare(lowerCase, upperCase,
  StringComparison.CurrentCultureIgnoreCase);
int caseSensitiveResult = string.Compare(lowerCase,
  StringComparison.CurrentCulture);

The caseSensitiveResult value is -1 (indicating that lowerCase is "less than" upperCase) and the caseInsensitiveResult is zero (indicating that lowerCase "equals" upperCase).

I_Al-thamary
  • 3,385
  • 2
  • 24
  • 37
1

How about using StringComparison.CurrentCultureIgnoreCase instead?

decyclone
  • 30,394
  • 6
  • 63
  • 80
  • 5
    -1: This answer is insufficient. Please see @ocean4dream's answer: http://stackoverflow.com/a/13965429/109941. – Jim G. Jun 04 '14 at 14:49
  • @decyclone: It's slower than OrdinalIgnoreCase, but maybe relevant in some cases. Therefore I won't give -1. https://stackoverflow.com/questions/2749662/string-comparison-invariantcultureignorecase-vs-ordinalignorecase – Csaba Toth Jan 31 '16 at 21:40
  • Also https://stackoverflow.com/questions/72696/which-is-generally-best-to-use-stringcomparison-ordinalignorecase-or-stringco – Csaba Toth Jan 31 '16 at 21:42
-12

you can always use functions: .ToLower(); .ToUpper();

convert your strings and then compare them...

Good Luck

  • I do not think this would solve his problem. Also mark that this question is already more than 4 years old. – Vojtěch Dohnal Oct 31 '14 at 10:05
  • 12
    This creates a new string, so I consider this very inefficient. Because to create this new string all characters will be checked and converts to the desired case, then the comparision has to check all the characters again. So it uses more memory and processing power. – Air2 Nov 06 '14 at 10:22
  • 7
    This is very bad practice because of the memory allocation. – Thorbjørn Lindeijer Feb 18 '15 at 10:18
  • Not only this is unnecessary memory allocation and inefficient; it also fails the [Turkey test](http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html). – dmitry Dec 04 '19 at 13:45
  • This can be a very valuable approach *in some circumstances*. Specifically, where you plan to compare the string to many others, perhaps with a switch() or elseif ladder (eg when checking against a list of commands that you control, so know won't be affected by I18N lowercasing issues; or against a wordle wordlist). Doing every compare case-insensitively may not be very performant, but more importantly, isn't as readable as `str == "a"` or `case "a"`, or a hashtable check. For the question at hand, though... yeah, best to do it the Right Way. – Dewi Morgan Mar 30 '22 at 03:00