如何从 Powershell 中的字符串转换为 UInt64?字符串到数字的转换

How to convert to UInt64 from a string in Powershell? String-to-number conversion

考虑以下 Powershell 片段:

[Uint64] $Memory = 1GB
[string] $MemoryFromString = "1GB"
[Uint64] $ConvertedMemory = [Convert]::ToUInt64($MemoryFromString)

第三行失败:

Exception calling "ToUInt64" with "1" argument(s): "Input string was not in a correct format."
At line:1 char:1
+ [Uint64]$ConvertedMemory = [Convert]::ToUInt64($MemoryFromString)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : FormatException

如果我检查$Memory的内容:

PS C:\> $Memory
1073741824

效果不错。

那么,如何在 Powershell 中将值“1GB”从字符串转换为 UInt64?

您的问题是 ToUint64 不理解 Powershell 语法。您可以通过以下方式解决它:

($MemoryFromString / 1GB) * 1GB

因为$MemoryFromString会在除法之前转换它的数值。

这是有效的,因为在除法点 Powershell 尝试使用其规则将字符串转换为数字,而不是烘焙到 ToUInt64 中的 .Net 规则。作为转换的一部分,如果发现 GB 后缀并应用它的规则将 "1GB" 字符串扩展为 1073741824

编辑:或者正如 PetSerAl 指出的那样,您可以这样做:

($MemoryFromString / 1)

补充 :

只有结果变量的类型约束 ([uint64] $ConvertedMemory = ...) 才能确保将 ($MemoryFromString / 1) 转换为 [uint64] ([System.UInt64])。

表达式$MemoryFromString / 1的结果实际上是[int]类型([System.Int32]):

PS> ('1gb' / 1).GetType().FullName
System.Int32

因此,要确保表达式 本身 returns 是一个 [uint64] 实例,您必须使用 cast :

PS> ([uint64] ('1gb' / 1)).GetType().FullName
System.Int64

注意计算周围所需的 (...),因为 [uint64] 转换将仅适用于 '1gb'(因此失败)。
或者,('1gb' / [uint64] 1) 也可以。

注:

  • '1gb' - 0 也可以,
  • 不是 '1gb' * 1'(实际上是 no-op)或 '1gb' + 0(结果为字符串 '1gb0'),因为运算符 *+ 具有 string 类型的 LHS 执行 string 操作(分别是复制和连接)。

PowerShell 中的自动 string-to-number 转换 数字文字:

当PowerShell执行隐式数字转换时,包括在执行mixed-numeric-type计算和解析源代码中的数字文字时,它方便地auto-selects 一个“大”到足以容纳结果的数值类型.

隐式string-to-number转换中,PowerShell 可以方便地识别文字支持的相同格式在源代码中:

  • number-base prefixes(对于integers only): 0x for hexadecimal integers, 0b for binary integers (PowerShell [核心] 7.0+)

  • 编号-类型 后缀:L [long] ([System.Int64]), D [decimal] ([System.Decimal]);例如,'1L' - 0 产生 [long].
    注意C#M代替D,而是用D指定[System.Double];此外,C# 支持几个额外的后缀。

    • PowerShell [Core] 6.2+ 现在支持 附加后缀 : Y ([sbyte]), UY ([byte]), S ([int16]), US ([uint16]), U ([uint32] [uint64],根据需要)和 UL ([uint64]).

    • PowerShell [Core] 7.0+ 额外支持后缀 n ([bigint])

    • 以后有什么进展可以关注官方帮助主题,about_Numeric_Literals.

  • floating-point表示如1.23(仅十进制);请注意,PowerShell 仅将 . 识别为小数点,不考虑当前的文化.

  • 指数表示法(仅十进制);例如,'1.0e3' - 1 产生 999.

  • 自己的binary-multiplier后缀,kb,mb,gb,tbpb(对于乘数 [math]::pow(2, 10) == 1024[math]::pow(2, 20) == 1048576、...);例如,'1kb' - 1 产生 1023;请注意,这些后缀是 PowerShell-specific,因此 .NET 框架 number-parsing 方法 识别它们。

number-conversion规则很复杂,但这里有一些关键点:

这是我自己的实验。如果我错了请告诉我。
类型由它们的 PS 类型加速器表示并映射到 .NET 类型,如下所示:
[int] ... [System.Int32]
[long] ... [System.Int64]
[decimal] ... [System.Decimal]
[float] ... [System.Single]
[double] ... [System.Double]

  • PowerShell 从不 auto-selects 无符号 整数类型.

    • 注意:在 PowerShell [Core] 6.2+ 中,您可以使用类型后缀 USUUL(见上文) 强制处理为无符号类型(正数);例如,0xffffffffffffffffU
    • 对于十六进制 数字字面量 这可能是意想不到的;例如,[uint32] 0xffffffff 失败 ,因为 0xfffffffffirst - 隐含地 - 转换为 signed 类型 [int32],它产生 -1,作为 signed 值,不能转换为 unsigned 输入 [uint32].
    • 解决方法:
      • 附加 L 以强制解释为 [int64],这会产生预期的正值 4294967295,在这种情况下,转换为 [uint32] 会成功。
      • 该技术不适用于 0x7fffffffffffffff ([long]::maxvalue) 以上的值,但是,在这种情况下,您可以使用 string 转换:[uint64] '0xffffffffffffffff'
  • PowerShell 根据需要扩展 整数类型:

    • For decimal integer literals / strings, widening goesbeyond 整数类型到 [System.Decimal],然后根据需要 [Double];例如:

      • (2147483648).GetType().Name 产生 Int64,因为该值为 [int32]::MaxValue + 1,因此被隐式扩展为 [int64]

      • (9223372036854775808).GetType().Name 产生 Decimal,因为该值为 [int64]::MaxValue + 1,因此被隐式扩展为 [decimal]

      • (79228162514264337593543950336).GetType().Name 产生 Double,因为值为 [decimal]::MaxValue + 1,因此被隐式扩大为 [double]

    • 对于十六进制(总是整数)文字/字符串,扩展停止在[int64]:

      • (0x100000000).gettype().name 产生 Int64,因为该值为 [int32]::MaxValue + 1,因此被隐式扩展为 [int64]

      • 0x10000000000000000,也就是 [int64]::MaxValue + 1不会 晋升为 [System.Decimal] 因为 [=303] =]十六进制 并解释为数字,因此 失败

    • 注意:以上规则适用于单个文字/字符串,但在 表达式中加宽 可能会立即加宽到 [double](没有考虑 [decimal]) - 见下文。

  • PowerShell 似乎 从来没有 auto-selects 整数类型 [int]:

    • ('1' - 0).GetType().FullName 产生 System.Int32[int]),即使整数 1 适合 [int16] 甚至 [byte]
  • 计算结果永远不会使用比任一操作数更小的类型:

    • 1 + [long] 1[long] 1 + 1 都会产生 [long](即使结果可以适合更小的类型)。
  • 也许出乎意料,PowerShell auto-selects floating-point 输入[double] 计算结果大于任一操作数的类型整数类型可以适合,即使结果可以适合更大整数 类型:

    • ([int]::maxvalue + 1).GetType().FullName 产生 System.Double[double]),即使结果适合 [long] 整数。
    • 如果其中一个操作数是 large-enough 整数类型,则结果是该类型:([int]::maxvalue + [long] 1).GetType().FullName 产生 System.Int64[long])。
  • 在计算中涉及至少一个 floating-point 类型总是导致 [double],即使与整数类型混合或使用全部-[float] 个操作数:

    • 1 / 1.0 and 1.0 / 1 and 1 / [float] 1 and [float] 1 / 1 and [float] 1 / [float] 1 all yield a [double]
  • 数字文字在源代码中不使用类型后缀:

    • Decimal integer 文字被解释为以下可以适合的最小类型值:[int] > [long] > [decimal] > [double](!):

      • 1 产生一个 [int](如前所述,[int] 是最小的 auto-selected 类型)
      • 214748364(比 [int]::maxvalue 高 1)产生 [long]
      • 9223372036854775808(比 [long]::maxvalue 高 1)产生 [decimal]
      • 79228162514264337593543950336(比 [decimal]::maxvalue 高 1)产生 [double]
    • 十六进制整数文字被解释为以下类型中最小的可以适合值:[int] > [long];也就是说,与 decimal 文字不同,不支持大于 [long] 的类型; 警告设置高位的值会导致负数十进制数,因为PowerShell auto-selects 有符号整数类型:

      • 0x1 产生一个 [int]

      • 0x80000000 产生一个 [int] 是一个 负数 值,因为设置了高位:-2147483648 ,这是最小的 [int]数,如果你考虑符号([int]::MinValue)

      • 0x100000000(比[int](或[uint32])多1个)产生[long]

      • 0x10000000000000000(多了一个[long](或[uint64]))breaks,因为[long] 是支持的最大类型(“数字常量无效”)。

      • 确保十六进制文字结果为:

        • Windows PowerShell:首先使用类型后缀 L 强制解释为 [long],然后(可选)转换为 无符号类型;例如[uint32] 0x80000000L 产生 2147483648,但请注意,此技术仅适用于 0x7fffffffffffffff,即 [long]::maxvalue;如上所述,使用 字符串 的转换作为解决方法(例如 [uint64] '0xffffffffffffffff')。

        • PowerShell [Core] 6.2+:根据需要使用类型后缀 usuul;例如:0x8000us -> 32768 ([uint16]), 0x80000000u -> 2147483648 ([uint32]), 0x8000000000000000ul -> 9223372036854775808 ([uint64])

    • Binary integer 文字(PowerShell [Core] 7.0+)的解释方式与 十六进制个;例如,0b10000000000000000000000000000000 == 0x80000000 == -2147483648 ([int])

    • Floating-point指数符号 文字 (仅在 decimal 表示中被识别) 总是被解释为 [double],无论多小:

      • 1.01e0 都产生 [double]