gpt4 book ai didi

powershell - 为什么 `-lt` 对字符和字符串的行为不同?

转载 作者:行者123 更新时间:2023-12-04 14:56:41 25 4
gpt4 key购买 nike

我最近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

然后我尝试测试字符与单字符字符串:
[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

为了比较,我尝试使用区分大小写的小于运算符,但它显示 L > l这与 -lt相反返回字符。
"L" -clt "l"
False

"l" -clt "L"
True

比较是如何工作的,因为它显然不是使用 ASCII 值,为什么它对字符和字符串的行为不同?

最佳答案

非常感谢 PetSerAl感谢他的所有宝贵意见。

tl;博士 :

  • -lt-gt比较 [char]通过 Unicode 代码点数字化实例。
  • 令人困惑的是,也是如此-ilt , -clt , -igt , -cgt - 尽管它们只对字符串操作数有意义,但这是 PowerShell 语言本身的一个怪癖(见底部)。
  • -eq (及其别名 -ieq ),相比之下,比较 [char]不区分大小写的实例,这通常但不一定像不区分大小写的字符串比较( -ceq 再次严格进行数字比较)。
  • -eq/-ieq最终也进行数字比较,但首先使用不变区域性将操作数转换为其大写等价物;因此,这种比较并不完全等同于 PowerShell 的字符串比较,后者额外将所谓的兼容序列(不同的字符或什至被认为具有相同含义的序列;参见 Unicode equivalence)视为相等。
  • 换句话说: PowerShell 仅对 -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

    是什么让 [char] 不寻常的是它的实例是 通过 Unicode 代码点按原样在数字上相互比较,除了 -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')
  • -eq (及其别名 -ieq )首先将字符转换为大写,然后比较生成的 Unicode 代码点:

  • [char] 'A' -eq [char] 'a' # !! ALSO $true; equivalent of 65 -eq 65

    值得反射(reflection)的佛教转向:这个和那个: 在 PowerShell 的世界中,字符 'A' 既小于又等于 'a',这取决于您如何比较 .

    另外, 直接或间接 - 转换为大写后 - 比较 Unicode 代码点与将它们作为字符串进行比较不同 ,因为 PowerShell 的字符串比较还识别所谓的兼容序列,如果字符(甚至字符序列)具有相同的含义,则它们被认为是“相同的”(参见 Unicode equivalence);例如。:
    # 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

    请注意 前缀的使用 ic明确指定大小写匹配行为不足以强制进行字符串比较 ,即使概念上的运算符,例如 -ceq , -ieq , -clt , -ilt , -cgt , -igt只对字符串有意义。

    实际上,ic当应用于 -lt 时,前缀会被简单地忽略和 -gt比较时 [char]操作数 ;事实证明(与我最初的想法不同),这是一个 一般 PowerShell 陷阱 - 有关解释,请参见下文。

    顺便说一句: -lt-gt字符串比较中的逻辑不是数字,而是基于整理顺序 (一种以人为中心的排序方式,独立于代码点/字节值),在 .NET 术语中由文化控制(默认情况下由当前有效的文化控制,或者通过将文化参数传递给方法)。
    正如@PetSerAl 在评论中所展示的(与我最初声称的不同), PS 字符串比较使用不变区域性 , 不是当前的文化,因此无论当前的文化是什么,他们的行为都是相同的。

    幕后制作:

    正如@PetserAl 在评论中解释的那样,PowerShell 的解析不区分运算符的基本形式 i - 前缀形式;例如,两者 -lt-ilt被转换为相同的值, Ilt .
    因此, Powershell 无法为 -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.

    在后一种情况下,我会期望使用 -cgt将操作数强制转换为字符串,因为区分大小写的比较在字符串比较中只是一个有意义的概念,但这不是它的工作原理。

    如果您想更深入地了解 PowerShell 的运行方式,请参阅下面的 @PetSerAl 评论。

    关于powershell - 为什么 `-lt` 对字符和字符串的行为不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36096322/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com