Friday, February 29, 2008

Case Insensitive String Comparison is Teh Suck

Why is it so verbose to compare two strings in C# and see if they are equal, while ignoring case?

What I mean is this:  ("Apples" == "apples")  => false

Take the following examples, each of which does what I want it to, however there is so much noise code here that it really takes away from the readability of the code:

Assert.That(matches[0].Email.Equals(email, StringComparison.InvariantCultureIgnoreCase));

Assert.That(matches[0].Email.ToLower().Equals(email.ToLower()));
Assert.That(string.Compare(matches[0].Email, email) == 0);
Assert.That(Regex.Match(matches[0].Email, email, RegexOptions.IgnoreCase).Success);

Each one of these works, but I really wish this was a language feature.  Wouldn't it be nice to have a new operator syntax?
Assert.That(matches[0].Email ==? email);
//or
Assert.That(matches[0].Email ==~ email);
It turns out that we're not alone.  Ruby and Python have the same problem, however their regular expressions option is much more elegant looking (due to the languages having regex as a core feature).  This seems like such a common need that I'm surprised that this type of thing isn't built into the core of most languages.

Granted, there are concerns about how each one of these would behave, for example, how do you compare strings from two different cultures?  In my case I'm always dealing with English characters, but I fully understand the need to support internationalization.

What do you think?  Would you welcome a new operator to save your self some typing and improve readability?

Friday, February 29, 2008 10:48:00 AM (Central Standard Time, UTC-06:00)
You could always do some extension method...

public static bool iEquals(this string source, string value)
{
return source.ToLowerInvariant() == value.ToLowerInvariant();
}

string s = "Bob";
string s2 = "boB";
Assert.IsTrue(s.iEquals(s2));

But yes, I agree that a built in solution would be great.
Friday, February 29, 2008 11:06:40 AM (Central Standard Time, UTC-06:00)
Don't forget our good friend PowerShell:
--
1# "awesomeness" -eq "AWESOMENESS"
True
--

Out of the box! Huzzah!

Then, if you actually WANT case sensitivity:
--
2# "awesomeness" -ceq "AWESOMENESS"
False
--

Huzzah again!

Of course, most of you by this point are clawing at your eyes trying to 'un-see' the -eq operator--yes, PowerShell inherits its comparison syntax from the "test" command in unix systems (thanks Bruce Payette/PowerShell in Action for that tidbit). Instead of == or =, you use -eq.

So there's both a positive, and a "not positive" aspect of doing comparisons in PowerShell.

Friday, February 29, 2008 11:13:05 AM (Central Standard Time, UTC-06:00)
Completely agree - I'm not positive about how I would prefer the syntax, but there is so much line noise when working with strings. I've started learning some Python and Ruby and it just pains me to go back to the verbosity of C#/VB.NET.

(PowerShell FTW Peter!)
Friday, February 29, 2008 1:00:54 PM (Central Standard Time, UTC-06:00)
I'm torn on stuff like this. On the one hand, quick and easy language syntax for the most common operation is nice. But on the other hand it can often be an "enabler" for bad code.

String comparison is complex enough of an issue that I tend to think that it should be fairly explicit (and thus typically more verbose).
Here's a good write-up of some potential issues you can run into without realizing it.
http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html
Friday, February 29, 2008 4:16:07 PM (Central Standard Time, UTC-06:00)
String comparisons have always annoyed me. You almost never want what the default is.
Saturday, March 01, 2008 12:21:10 AM (Central Standard Time, UTC-06:00)
I agree with Will Shaver! Extension Methods can solve this problem.

public static class ExtensionMethods
{
public static bool BetterEquals(this string strA,string strB)
{
if ((strA == null) && (strB != null)) return false;

return strA.Equals(strB, StringComparison.OrdinalIgnoreCase);
}

}


Saturday, March 01, 2008 11:29:55 AM (Central Standard Time, UTC-06:00)
Yes, that works in 2008. Unfortunately I'm still using 2005.

I'd settle for something like:
string name1 = "BoB";
string name2 = "bob";

name1.EquivalentTo(name2) => true

or something along those lines. The same thing would also be nice to have for the other string functions like .EndsWith() .StartsWith(), etc.
Ben Scheirman
Monday, March 03, 2008 1:02:02 PM (Central Standard Time, UTC-06:00)
Ben,

Both NUnit and MbUnits string asserts will match case

MbUnit
StringAssert.Equals

NUnit
StringAssert.Contains

Unless in both frameworks you say otherwise with StringAssert.AreEqualIgnoreCase

Of course it's not a constraint but the frameworks with out clutter will allow you to do what you ask.
Sunday, March 23, 2008 12:47:45 PM (Central Standard Time, UTC-06:00)
you could always use the NUnit Syntax Helpers.

Assert.That( a, Is.EqualTo( b ).IgnoreCase );
Comments are closed.
Share Dealing - Loans - Remortgage - Credit Card Consolidation