Is There a C# Case Insensitive Equals Operator

Is there a C# case insensitive equals operator?

Try this:

string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase);

How to ensure case insensitive comparison on strings when comparing unknown object types?

You can use another extension method like IsEqual, then inside the method check if the parameter is string, compare in your preferred way.

For example, something like the following code. I haven't tested the functionality, it's just demonstrating the idea:

public static class ObjectExtesions
{
public static bool IsEqual(this object left, object right)
{
if (left == null && right == null)
return true;
if (left != null && right != null)
{
if (left is string && right is string)
return ((string)left).Equals((string)right,
StringComparison.InvariantCultureIgnoreCase);
else
return left.Equals(right);
}
return false;
}
}

Ignoring case sensitive in c#

You can (and should always) do this to compare strings instead of using ==:

if (userData[fnIndex].ToString().Equals(
"FIRSTNAME1", StringComparison.CurrentCultureIgnoreCase))

Also, "FIRSTNAME1" and "LASTNAME1" should be made into constants.

Why does string.Equals work for case insensitivity by default?

Actually, all LINQ expressions against CRM context is converted by LINQ provider to QueryExpression. And string.Equals filter is defined there as case insensitive, so you get this result.

About your attempt with StringComparison.OrdinalIgnoreCase, IMO it could be (and I think it is) that the provider does not support that method with a second parameter (I've tried and it does not return desired result with other comparison types either).

Possible to create case insensitive string class?

It wouldn't behave "exactly like a string". The string type is special and is baked into the language spec. C# strings exhibit special behavior, such as

  • being a reference type, that gets passed by value. Reference types are normally passed by...well...reference.

  • are interned by default. That means that there is only ever a single instance of a given string. The following code results in the creation of just a single string: a, b and c all point to exactly the same instance of the string quick. That means that Object.ReferenceEquals() is true when comparing any two:

    string a = "The quick brown dog...".Substring(4,5) ;
    string b = new string(new char[]{'q','u','i','c','k'});
    string c = new StringBuilder().
    .Append('q')
    .Append('u')
    .Append('i')
    .Append('c')
    .Append('k')
    .ToString()
    ;

[edited to note: while one might think that this should be possible, a little fiddling around suggests that one can't actually create a custom implementation/subtype of CompareInfo as it has no public constructors and its default constructor is internal. More in the answers to this question: Globally set String.Compare/ CompareInfo.Compare to Ordinal

Grrr...]

What you could do is this:

String comparisons are done using the current culture's collation/comparison rules. Create a custom culture for your app, say, a copy of the the US culture that uses the collation/comparison rules you need. Set that as the current culture and Bob's-yer-uncle.

You'll still get compiler/ReSharper whines because you're doing string comparisons without specifying the desired comparison semantics, but your code will be clean.

For more details, see

  • https://msdn.microsoft.com/en-us/library/kzwcbskc(v=vs.90).aspx
  • https://msdn.microsoft.com/en-us/library/se513yha(v=vs.100).aspx

Case insensitive 'Contains(string)'

To test if the string paragraph contains the string word (thanks @QuarterMeister)

culture.CompareInfo.IndexOf(paragraph, word, CompareOptions.IgnoreCase) >= 0

Where culture is the instance of CultureInfo describing the language that the text is written in.

This solution is transparent about the definition of case-insensitivity, which is language dependent. For example, the English language uses the characters I and i for the upper and lower case versions of the ninth letter, whereas the Turkish language uses these characters for the eleventh and twelfth letters of its 29 letter-long alphabet. The Turkish upper case version of 'i' is the unfamiliar character 'İ'.

Thus the strings tin and TIN are the same word in English, but different words in Turkish. As I understand, one means 'spirit' and the other is an onomatopoeia word. (Turks, please correct me if I'm wrong, or suggest a better example)

To summarise, you can only answer the question 'are these two strings the same but in different cases' if you know what language the text is in. If you don't know, you'll have to take a punt. Given English's hegemony in software, you should probably resort to CultureInfo.InvariantCulture, because it will be wrong in familiar ways.

What is the correct way to compare char ignoring case?

It depends on what you mean by "work for all cultures". Would you want "i" and "I" to be equal even in Turkey?

You could use:

bool equal = char.ToUpperInvariant(x) == char.ToUpperInvariant(y);

... but I'm not sure whether that "works" according to all cultures by your understanding of "works".

Of course you could convert both characters to strings and then perform whatever comparison you want on the strings. Somewhat less efficient, but it does give you all the range of comparisons available in the framework:

bool equal = x.ToString().Equals(y.ToString(), 
StringComparison.InvariantCultureIgnoreCase);

For surrogate pairs, a Comparer<char> isn't going to be feasible anyway, because you don't have a single char. You could create a Comparer<int> though.

case insensitive key comparison for KeyValuePair

I liked the overload solution but it needed completion via http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

Researching @Jeppe Stig Nielsen showed that OrdinalIgnoreCase was most appropriate for my comparisons.

"Comparisons made using OrdinalIgnoreCase are behaviorally the composition of two calls: calling ToUpperInvariant on both string arguments, and doing an Ordinal comparison." [http://msdn.microsoft.com/en-us/library/ms973919.aspx]

Based on this citation I chose return this.Key.ToUpperInvariant().GetHashCode(); in the GetHashCode() overload.

Class Implementation

public class MyKeyValuePair
{
private readonly KeyValuePair<string, int> myKeyValuePair;
public MyKeyValuePair(string key, int value)
{
myKeyValuePair = new KeyValuePair<string, int>(key, value);
}

public string Key { get { return myKeyValuePair.Key; } }
public int Value { get { return myKeyValuePair.Value; } }

public static bool operator ==(MyKeyValuePair a, MyKeyValuePair b)
{
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
if (((object)a == null) || ((object)b == null))
{
return false;
}
return a.Key.Equals(b.Key, StringComparison.OrdinalIgnoreCase);
}
public static bool operator !=(MyKeyValuePair a, MyKeyValuePair b)
{
return !(a == b);
}

public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
MyKeyValuePair p = obj as MyKeyValuePair;
if ((object)p == null)
{
return false;
}
return this.Key == p.Key;
}

public bool Equals(MyKeyValuePair obj)
{
if ((object)obj == null)
{
return false;
}
return this.Key.Equals(obj.Key, StringComparison.OrdinalIgnoreCase);
}

public override int GetHashCode()
{
return this.Key.ToUpperInvariant().GetHashCode();
}
}

Test Method

public void MyKeyValuePairCaseInsensitiveKeyComparisonWorksCorrectly()
{
var x = new MyKeyValuePair("testvalue", 5);
var y = new MyKeyValuePair("testvalue", 6);
var z = new MyKeyValuePair("testvalue", 7);

Assert.True(x == x, "== identity");
Assert.True((x == y) == (y == x), "equals commutative");
Assert.True(x == y, "== if x == y");
Assert.True(y == x, "== and y == z");
Assert.True(x == z, "== then x equals z");
for (var successive_invocations = 0; successive_invocations < 3; successive_invocations++)
{
Assert.True(x == y, "== successive invocations");
}
Assert.False(x == null);

Assert.True(x.Equals(x), "equals identity");
Assert.True(x.Equals(y) == y.Equals(x), "equals commutative");
Assert.True(x.Equals(y), "equals if x == y");
Assert.True(y.Equals(x), "equals and y == z");
Assert.True(x.Equals(z), "equals then x equals z");
for (var successive_invocations = 0; successive_invocations < 3; successive_invocations++)
{
Assert.True(x.Equals(y), "equals successive invocations");
}
Assert.False(x.Equals(null));

// show correct behavior
var capi = "I";
var lowi = "i";
var capti = "İ";
var lowti = "ı";

Assert.True(capi.Equals(lowi, StringComparison.OrdinalIgnoreCase), "capi == lowi");
Assert.False(capi.Equals(capti, StringComparison.OrdinalIgnoreCase), "capi != capti");
Assert.False(capi.Equals(lowti, StringComparison.OrdinalIgnoreCase), "capi != lowti");

Assert.False(lowi.Equals(capti, StringComparison.OrdinalIgnoreCase), "lowi != capti");
Assert.False(lowi.Equals(lowti, StringComparison.OrdinalIgnoreCase), "lowi != lowti");

Assert.False(capti.Equals(lowti, StringComparison.OrdinalIgnoreCase), "capti != lowti");

//test actual behavior
var a = new MyKeyValuePair(capi, 1);
var b = new MyKeyValuePair(lowi, 2);
var c = new MyKeyValuePair(capti, 3);
var d = new MyKeyValuePair(lowti, 4);

Assert.True(a.Equals(b), "a == b");
Assert.False(a.Equals(c), "a != c");
Assert.False(a.Equals(d), "a != d");

Assert.False(b.Equals(c), "b != c");
Assert.False(b.Equals(d), "b != d");

Assert.False(c.Equals(d), "c != d");
}


Related Topics



Leave a reply



Submit