我最近answered a SO-question关于使用-lt
或-gt
使用字符串。我的回答是基于something I've read earlier,它说-lt
一次比较每个字符串中的一个字符,直到ASCII值不等于另一个字符串。此时结果(低/等/更大)决定。根据该逻辑,"Less" -lt "less"
应返回True
,因为L
的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
似乎我可能错过了一个关键部分:测试不区分大小写
#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
然后我尝试测试char vs single-character-string:
[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
为了进行比较,我尝试使用区分大小写的less-than运算符,但是它表示L > l
与-lt
为chars返回的内容相反。
"L" -clt "l"
False
"l" -clt "L"
True
比较是如何工作的,因为它显然不是使用ASCII值,为什么字符与字符串的行为不同?
答案 0 :(得分:3)
非常感谢PetSerAl所有宝贵的意见。
<强> TL;医生强>:
-lt
和-gt
通过 Unicode codepoint 比较[char]
个实例数字。
-ilt
,-clt
,-igt
,-cgt
也是如此 - 尽管它们只对 string 操作数有意义,但是& #39; PowerShell语言本身的一个怪癖(见下)。 -eq
(及其别名-ieq
)比较[char]
个实例不区分大小写,这通常是不一定喜欢不区分大小写的字符串比较(-ceq
再次比较严格数字)。
-eq
/ -ieq
最终还会比较数字,但首先使用不变文化将操作数转换为大写等值;因此,这种比较并不完全等同于PowerShell的字符串比较,后者还识别所谓的兼容序列(不同的字符或甚至被认为具有相同含义的序列;请参阅{{ 3}})同等。 -eq
/ -ieq
与[char]
个操作数的行为,并且以几乎但不完全相同的方式执行此操作字符串比较。这种区别会导致反直觉行为,例如[char] 'A' -eq [char] 'a'
和[char] 'A' -lt [char] 'a'
两者返回$true
。
为了安全起见:
[int]
。[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
使 [char]
异常的原因是它的实例通过Unicode代码点数字地进行比较-eq
强>
-ieq
,ceq
和-lt
通过Unicode代码点直接比较 ,并且 - 反直觉 - 所以-gt
,{{ 1}},-ilt
和-clt
:-igt
-cgt
(及其别名[char] 'A' -lt [char] 'a' # $true; Unicode codepoint 65 ('A') is less than 97 ('a')
)首先将字符转换为大写,然后比较生成的Unicode代码点:-eq
值得反思的是这个佛教转向:这个和:PowerShell世界中的,角色&#39; A&#39;小于且等于&#39; a&#39;,具体取决于您的比较方式。
此外,直接或间接 - 转换为大写后 - 比较Unicode代码点与将它们作为 strings 进行比较并不相同,因为PowerShell的字符串比较另外识别所谓的兼容序列,其中字符(或甚至字符序列)被认为是#34;相同的&#34;如果它们具有相同的含义(参见Unicode equivalence); e.g:
-ieq
请注意,使用前缀[char] 'A' -eq [char] 'a' # !! ALSO $true; equivalent of 65 -eq 65
或# 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
到显式指定大小写匹配行为不足以强制 string 比较,即使概念运算符,例如i
,c
,-ceq
,-ieq
,-clt
,{{ 1}}只对字符串有意义。
有效的是,-ilt
和-cgt
前缀在应用于-igt
和i
时只需忽略,同时{{1}操作数;事实证明(与我原先的想法不同),这是一个一般的PowerShell陷阱 - 请参阅下面的解释。
顺便说一下:字符串比较中的 c
和-lt
逻辑不是数字,但基于整理订单 (一种独立于代码点/字节值的人类中心排序方式),在.NET术语中由 culture 控制(或者默认情况下,当前有效的方法,或通过将参数传递给方法)
正如@PetSerAl在评论中演示(与我最初声明的不同), PS字符串比较使用不变文化,而不是当前文化,所以他们的行为是一样的,不管现在的文化是什么。
在幕后:
正如@PetserAl在评论中解释的那样,PowerShell的解析并没有区分运算符的基本形式-gt
- 前缀形式;例如,[char]
和-lt
都转换为相同的值-gt
。
因此, Powershell 无法为i
与-lt
,-ilt
与Ilt
实施不同的行为,... ,因为它在语法级别上对它们的处理方式相同。
这导致某些反直觉行为,因为在比较区分大小写无意义的数据类型时,操作符前缀有效忽略 - 而不是被强制转换为人们可能期望的字符串; e.g:
-lt
在后一种情况下,我会期望使用-ilt
来强制操作数到字符串,因为区分大小写的比较只是字符串比较中的一个有意义的概念,但这不是它的工作原理。 / p>
如果您想深入了解PowerShell的运作方式,请参阅下面的@ PetSerAl评论。
答案 1 :(得分:1)
在处理字符串/字符时,不太确定除了比较之外的其他内容都是正确的。如果您想进行有序比较,请进行有序比较,然后根据该结果得到结果。
Best Practices for Using Strings in the .NET Framework
[string]::Compare('L','l')
returns 1
和
[string]::Compare("L","l", [stringcomparison]::Ordinal)
returns -32
不知道在这里添加什么来帮助澄清。