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