Home > Enterprise >  Comparing '1' and '_' in PowerShell gives unexpected result
Comparing '1' and '_' in PowerShell gives unexpected result

Time:12-09

On comparing '1' with '_' the answer I'm expecting is '1' < '_' because their Ascii values are 49 and 95 respectively. But the answer is the other way. For that matter, even ':' instead of '_' gives the same result.

[byte][char]'1' -gt [byte][char]'_'
>> False

which makes sense. However:

'1' -gt '_'
>> True

Would appreciate any pointers on what I may be missing here. In essence I'm looking for a reliable way to lexicographically compare strings in powershell. Thanks!

CodePudding user response:

Let's break down your two examples.

[byte][char]'1' -gt [byte][char]'_'

In this example you're comparing a byte to a byte. It is important to note that byte and char are both numeric values. The only real difference is that a char is 16 bits (so it can represent Unicode characters) and a byte is only 8 bits. Casting a string to a char gets the numeric representation of the character in the string (provided the string only contains a single character).

This means that [byte][char]'1' results in the number 49 and [byte][char]'_' results in 95. The expression will evaluate to false since 49 is not greater than 95.

Now let's look at your second example

'1' -gt '_'

In this example, you're comparing a string to a string. When comparing two strings using -gt, -ge, -lt, or -le, it uses the alphabetical sort order to determine whether or not the expression should be true or false, not the numeric value of the character. If one string is sorted before another string, the first string is considered less than the second and vice versa.

You can see this behavior if you use the Sort-Object cmdlet.

'1', '2', '3', '_' | Sort-Object
# returns '_', '1', '2', '3'

This means that your second example will return true because in the sort order implemented by .NET, _ comes before 1.

The order of special characters can vary by language and/or culture as there does not appear to be a standard, however it is pretty universally accepted that special characters should be sorted before numbers and letters.

CodePudding user response:

Your first example is using Byte.CompareTo(Byte) whereas your second example is using String.CompareTo(String).

'1' -gt '_' returns $true because 1 follows _.

Two different ways you could see it:

'1'.CompareTo('_')                  # => 1
([char] '1').CompareTo([char] '_')  # => -46

'1', '_' | Sort-Object              # => `_` goes first
'1', '_' -as [char[]] | Sort-Object # => `1` goes first
  • Related