What is the correct way to compare char ignoring case?

C#.NetStringComparisonChar

C# Problem Overview


I'm wondering what the correct way to compare two characters ignoring case that will work for all cultures. Also, is Comparer<char>.Default the best way to test two characters without ignoring case? Does this work for surrogate-pairs?

EDIT: Added sample IComparer<char> implementation

If this helps anyone this is what I've decided to use

public class CaseInsensitiveCharComparer : IComparer<char> {
    private readonly System.Globalization.CultureInfo ci;
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) {
        this.ci = ci;
    }
    public CaseInsensitiveCharComparer()
        : this(System.Globalization.CultureInfo.CurrentCulture) { }
    public int Compare(char x, char y) {
        return Char.ToUpper(x, ci) - Char.ToUpper(y, ci);
    }
}

// Prints 3
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer()));

C# Solutions


Solution 1 - C#

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.

Solution 2 - C#

As I understand it, there isn't really a way that will "work for all cultures". Either you want to compare characters for some kind of internal, non-displayed-to-the-user reason (in which case you should use the InvariantCulture), or you want to use the CurrentCulture of the user. Obviously, using the user's current culture will mean that you will get different results in different locales, but they will be consistent with what your users in those locales will expect.

Without knowing more about WHY you are comparing two characters, I can't really advise you on which one you should be using.

Solution 3 - C#

I would recommend comparing uppercase, and if they don't match then comparing lowercase, just in case the locale's uppercasing and lowercasing logic behave slightly different.

Addendum

For example,

int CompareChar(char c1, char c2)
{
    int  dif;

    dif = char.ToUpper(c1) - char.ToUpper(c2);
    if (diff != 0)
        dif = char.ToLower(c1) - char.ToLower(c2);
    return dif;
}

Solution 4 - C#

What I was thinking that would be available within the runtime is something like the following

public class CaseInsensitiveCharComparer : IComparer<char> {
    private readonly System.Globalization.CultureInfo ci;
    public CaseInsensitiveCharComparer(System.Globalization.CultureInfo ci) {
        this.ci = ci;
    }
    public CaseInsensitiveCharComparer()
        : this(System.Globalization.CultureInfo.CurrentCulture) { }
    public int Compare(char x, char y) {
        return Char.ToUpper(x, ci) - Char.ToUpper(y, ci);
    }
}

// Prints 3
Console.WriteLine("This is a test".CountChars('t', new CaseInsensitiveCharComparer()));

Solution 5 - C#

string.Compare("string a","STRING A",true)

It will work for every string

Solution 6 - C#

You could try:

    class Test{
    static int Compare(char t, char p){
        return string.Compare(t.ToString(), p.ToString(), StringComparison.CurrentCultureIgnoreCase);
    }
}

But I doubt this is the "optimal" way to do it, but I'm not all of the cases you need to be checking...

Solution 7 - C#

I know this is an old post, but things have changed since then.

The question above can be answered by using an extension. This would extend the char.Equals to allow for locality and case insensitivity.

In an extension class, add something such as:

internal static Boolean Equals(this Char src, Char ch, StringComparison comp)
{
    Return $"{src}".Equals($"{ch}", comp);
}

I'm currently at work, so can't check this, but it should work.

Andy

Solution 8 - C#

You can provide last argument as true for caseInsensetive match

string.Compare(lowerCase, upperCase, true);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrett RyanView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Jon GrantView Answer on Stackoverflow
Solution 3 - C#David R TribbleView Answer on Stackoverflow
Solution 4 - C#Brett RyanView Answer on Stackoverflow
Solution 5 - C#SergioView Answer on Stackoverflow
Solution 6 - C#ahawkerView Answer on Stackoverflow
Solution 7 - C#AndyView Answer on Stackoverflow
Solution 8 - C#rushi parikhView Answer on Stackoverflow