String.Compare not same as using relational operators to compare upper/ lowercase

Solitaire

Well-known member
Joined
Jun 28, 2004
Messages
465
Location
New York
Programming Experience
10+
If String.Compare uses the ASCII/Unicode values, then how come it places the lowercase values higher than the uppercase? It only works correctly when comparing the same case with different letters. Changing the CultureInfo makes no difference. Using relational operators to compare upper with lowercase strings or same case strings works correctly with the ASCII values.

VB.NET:
    Sub Main()
        Dim first, second As String
        first = "A"
        second = "a"
        Console.WriteLine("Using relational operators:")
        If first > second Then
            Console.WriteLine(first & " > " & second)
        ElseIf first < second Then
            Console.WriteLine(first & " < " & second)
        Else
            Console.WriteLine(first & " = " & second)
        End If
        Console.WriteLine(vbCrLf & "Using String.Compare: (places lowercase first)")
        Console.WriteLine("Value returned is " & String.Compare(first, second))
        If String.Compare(first, second, False) > 0 Then
            Console.WriteLine(first & " > " & second)
        ElseIf String.Compare(first, second, False) < 0 Then
            Console.WriteLine(first & " <  " & second)
        Else
            Console.WriteLine(first & " = " & second)
        End If
        'Using String.Compare with True (case insensitive) finds them equal.
        Console.ReadLine()
    End Sub

Why is it not using the ASCII/Unicode values? This can be confusing to my students after explaining that data is sorted using ASCII values and showing them how it works with relational operators.

Furthermore, using the Array.Sort method with upper and lowercase letters returns bizarre results. For example,

VB.NET:
    Sub Main()
        Dim stringarray() As String = {"a", "b", "C", "A", "B", "c"}
        Array.Sort(stringarray)
        For x As Integer = 0 To 5
            Console.WriteLine(stringarray(x))
        Next x
        Console.ReadLine()
    End Sub

The result is: a A b B c C

It should sort all the lowercase and uppercase letters separately. Is this some kind of bug?
 
According to String.Compare Method help:
The comparison is performed using word sort rules. For more information about word, string, and ordinal sorts, see System.Globalization.CompareOptions.
You can use one of the String.Compare overloads that take a StringComparison value to set ordinal comparison. The CompareOptions enum that was mentioned is a property of the CultureInfo.CompareInfo.
Same goes for Array.Sort, you can use a version where you specify custom sort order.

According to Comparison Operators (Visual Basic) article
When you compare strings, the string expressions are evaluated based on their alphabetical sort order, which depends on the Option Compare setting.
Default is Option Compare Binary.
 
Exactly how would that be coded?

I already tried:
Dim compareResult As Integer = String.Compare(first, second, False, Globalization.CultureInfo.CurrentCulture)
and
Dim compareResult As Integer = String.Compare(first, second, False, Globalization.CultureInfo.InvariantCulture)

Both still sort with lowercase first. No other suitable parameters are available.

And how would you code the Array.Sort() method? I tried to apply various parameters but none of them were accepted.
 
Hi Solitaire,

Does this help at all? It does what you want but not sure if it's what you want to expose to students. See here:-

VB.NET:
Dim myLetters() As String = {"b", "A", "a", "c", "B", "C", "D", "d"}
Dim mySortedLetters() As String = myLetters.OrderBy(Function(x) If(AscW(x) >= 97, 1, 2)).ThenBy(Function(x) AscW(x)).ToArray
MsgBox(String.Concat(mySortedLetters))

Ignore the first example above, it was the wrong way round anyway. Here's a better way:-

VB.NET:
Dim myLetters() As String = {"b", "A", "a", "c", "B", "C", "D", "d"}
Array.Sort(myLetters, StringComparer.Ordinal)
MsgBox(String.Concat(myLetters))

Hope that helps,

Cheers,

Ian
 
Last edited:
Thank you, Ian, that works nicely.

JohnH, you are being very cryptic. I tried the following, but it gave me an error:

VB.NET:
        If StringComparison.Ordinal.CompareTo(first) > StringComparison.Ordinal.CompareTo(second) Then
            Console.WriteLine(first & " > " & second)
        ElseIf StringComparison.Ordinal.CompareTo(first) < StringComparison.Ordinal.CompareTo(second) Then
            Console.WriteLine(first & " <  " & second)
        Else
            Console.WriteLine(first & " = " & second)
        End If

Please be more specific. Thank you.

Note: I tried placing Option Compare Text at the top of the code listed in my first post.
It placed uppercase first using String.Compare, which is what I wanted.
However, it caused case insensitivity using relational operators, so that comparison no longer works.
I would like to be able to use String.Compare with any parameters that would change its behavior, and without placing Option Compare Text on top.
 
Last edited:
I don't see how I am being cryptic, two times I have told you to use a String.Compare overload that take a StringComparison value as parameter, and specify ordinal comparison. The page I linked to last lists all String.Compare overloads, the third overload listed has this definition: Compare(String, String, StringComparison)
Will you be able to call this method?
 
Thank you, JohnH. I finally got it to work. I must have done something wrong when I tried it before because it had given me an error when I tried entering the 3rd parameter.
 
Found additional information. The String.Compare method returns 1 if the first string is greater than the second, -1 if it is less, and 0 if both are identical. The String.CompareOrdinal method returns the difference between the ASCII value of the first character in both strings; positive if the first is greater than the second, negative if less, and 0 if identical.

Summary:

Dim result As Integer, first, second As String
first = "A"
second = "a"
'with relational operators: A < a
result = String.Compare(first, second) '1, A > a
result = String.Compare(first, second, StringComparison.Ordinal) '-32, A < a
result = String.Compare(first, second, StringComparison.OrdinalIgnoreCase) '0, A = a
result = String.Compare(first, second, True) '0, A = a
result = first.CompareTo(second) '1, A > a
result = String.CompareOrdinal(first, second) '-32, A < a
 
Back
Top