Fro*_* F. 6 powershell operator-overloading operators
我最近回答了关于使用-lt
或-gt
使用字符串的问题.我的回答是基于我之前读过的一些内容,它说-lt
每次比较每个字符串中的一个字符,直到ASCII值不等于另一个字符串.此时结果(低/等/更大)决定.通过该逻辑,"Less" -lt "less"
应该返回True
因为L
具有比ASCII更低的ASCII字节值l
,但它不会:
[System.Text.Encoding]::ASCII.GetBytes("Less".ToCharArray())
76
101
115
115
[System.Text.Encoding]::ASCII.GetBytes("less".ToCharArray())
108
101
115
115
"Less" -lt "less"
False
Run Code Online (Sandbox Code Playgroud)
似乎我可能错过了一个关键部分:测试不区分大小写
#L has a lower ASCII-value than l. PS doesn't care. They're equal
"Less" -le "less"
True
#The last s has a lower ASCII-value than t. PS cares.
"Less" -lt "lest"
True
#T has a lower ASCII-value than t. PS doesn't care
"LesT" -lt "lest"
False
#Again PS doesn't care. They're equal
"LesT" -le "lest"
True
Run Code Online (Sandbox Code Playgroud)
然后我尝试测试char vs单字符串:
[int][char]"L"
76
[int][char]"l"
108
#Using string it's case-insensitive. L = l
"L" -lt "l"
False
"L" -le "l"
True
"L" -gt "l"
False
#Using chars it's case-sensitive! L < l
([char]"L") -lt ([char]"l")
True
([char]"L") -gt ([char]"l")
False
Run Code Online (Sandbox Code Playgroud)
为了比较,我尝试使用区分大小写的less-than运算符,但是它说的L > l
是与-lt
chars返回的相反.
"L" -clt "l"
False
"l" -clt "L"
True
Run Code Online (Sandbox Code Playgroud)
比较是如何工作的,因为它显然不是使用ASCII值,为什么它对字符与字符串的行为不同?
非常感谢PetSerAl的所有宝贵意见。
tl; 博士:
-lt
并通过Unicode codepoint 以数字方式-gt
比较[char]
实例。
-ilt
, -clt
, -igt
, -cgt
- 即使它们只对字符串操作数有意义,但这是 PowerShell 语言本身的一个怪癖(见底部)。-eq
(及其别名-ieq
),相比之下,不区分大小写地比较[char]
实例,这通常但不一定像不区分大小写的字符串比较(再次严格进行数字比较)。-ceq
-eq
/-ieq
最终也进行数值比较,但首先使用不变区域性将操作数转换为其大写等价物;因此,这种比较并不完全等同于 PowerShell 的字符串比较,后者还将所谓的兼容序列(不同的字符或什至被认为具有相同含义的序列;参见Unicode 等效)识别为相等。-eq
-ieq
[char]
,并且这样做的方式与不区分大小写的字符串比较几乎但不完全相同。这种区别导致违反直觉的行为,例如[char] 'A' -eq [char] 'a'
和[char] 'A' -lt [char] 'a'
都返回$true
。
为了安全起见:
[int]
如果您想要数字(Unicode 代码点)比较,请始终强制转换为。[string]
如果您想要字符串比较,请始终强制转换为。 有关背景信息,请继续阅读。
PowerShell 通常有用的运算符重载有时会很棘手。
请注意,在数字方面(无论是隐性或显性),PowerShell将字符([char]
([System.Char]
)实例) 数值,通过他们的Unicode代码点(不是ASCII)。
[char] 'A' -eq 65 # $true, in the 'Basic Latin' Unicode range, which coincides with ASCII
[char] '?' -eq 256 # $true; 0x100, in the 'Latin-1 Supplement' Unicode range
Run Code Online (Sandbox Code Playgroud)
是什么让[char]
难得的是,它的实例相互比较,数值为-是,通过统一代码点,除了与-eq
/-ieq
。
ceq
,-lt
以及-gt
比较直接由Unicode代码点,和-与直觉相反-这么做-ilt
,-clt
,-igt
和-cgt
:[char] 'A' -lt [char] 'a' # $true; Unicode codepoint 65 ('A') is less than 97 ('a')
Run Code Online (Sandbox Code Playgroud)
-eq
(及其别名-ieq
)首先将字符转换为大写,然后比较生成的 Unicode 代码点:[char] 'A' -eq [char] 'a' # !! ALSO $true; equivalent of 65 -eq 65
Run Code Online (Sandbox Code Playgroud)
值得反思这个佛教转向:这个和那个:在 PowerShell 的世界中,字符 'A' 既小于又等于 'a',这取决于你如何比较。
此外,直接或间接 - 转换为大写后 - 比较 Unicode 代码点与将它们作为字符串比较不同,因为 PowerShell 的字符串比较还识别所谓的兼容序列,其中字符(甚至字符序列)被认为是“相同的”如果它们具有相同的含义(参见Unicode 等价);例如:
# Distinct Unicode characters U+2126 (Ohm Sign) and U+03A9 Greek Capital Letter Omega)
# ARE recognized as the "same thing" in a *string* comparison:
"?" -ceq "?" # $true, despite having distinct Unicode codepoints
# -eq/ieq: with [char], by only applying transformation to uppercase, the results
# are still different codepoints, which - compared numerically - are NOT equal:
[char] '?' -eq [char] '?' # $false: uppercased codepoints differ
# -ceq always applies direct codepoint comparison.
[char] '?' -ceq [char] '?' # $false: codepoints differ
Run Code Online (Sandbox Code Playgroud)
需要注意的是使用前缀i
或c
以明确规定的情况下匹配的行为是不够给力的字符串对比,尽管在概念上运营商,如-ceq
,-ieq
,-clt
,-ilt
,-cgt
,-igt
才有意义与字符串。
实际上,当应用于和比较操作数时,i
和c
前缀会被简单地忽略-lt
-gt
[char]
;事实证明(与我最初的想法不同),这是一个常见的 PowerShell 陷阱- 请参阅下面的解释。
顺便说一句:-lt
与-gt
在逻辑串比较是不数字,但基于归类顺序(一个人,这在.NET术语是由控制排序独立编码点/字节值中的-centric方式)培养物(通过默认由所述一个当前有效,或通过将文化参数传递给方法)。
正如@PetSerAl 在评论中所展示的(与我最初声称的不同),PS 字符串比较使用不变文化,而不是当前文化,因此无论当前文化是什么,它们的行为都是相同的。
幕后花絮:
正如@PetserAl 在评论中解释的那样,PowerShell 的解析不区分运算符的基本形式及其i
前缀形式;例如,-lt
和-ilt
都被转换为相同的值,Ilt
。
因此,Powershell无法为vs. 、vs. 、 ...实现不同的行为-lt
-ilt
-gt
igt
,因为它在语法级别将它们视为相同的。
这会导致一些违反直觉的行为,因为在比较区分大小写没有意义的数据类型时,运算符前缀被有效地忽略了——而不是像人们预期的那样被强制转换为字符串;例如:
"10" -cgt "2" # $false, because "2" comes after "1" in the collation order
10 -cgt 2 # !! $true; *numeric* comparison still happens; the `c` is ignored.
Run Code Online (Sandbox Code Playgroud)
在后一种情况下,我希望使用-cgt
将操作数强制转换为字符串,因为区分大小写的比较只是字符串比较中的一个有意义的概念,但这不是它的工作原理。
如果您想更深入地了解 PowerShell 的运行方式,请参阅下面的 @PetSerAl 评论。