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

Mar*_*son 3 powershell type-conversion powershell-5.0

请考虑以下Powershell代码段:

[Uint64] $Memory = 1GB
[string] $MemoryFromString = "1GB"
[Uint64] $ConvertedMemory = [Convert]::ToUInt64($MemoryFromString)
Run Code Online (Sandbox Code Playgroud)

第3行失败了:

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
Run Code Online (Sandbox Code Playgroud)

如果我查看以下内容$Memory:

PS C:\> $Memory
1073741824
Run Code Online (Sandbox Code Playgroud)

这很好.

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

mkl*_*nt0 9

为了补充 肖恩的有用答案

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

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

PS> ('1gb' / 1).GetType().FullName
System.Int32
Run Code Online (Sandbox Code Playgroud)

因此,要确保表达式本身返回一个[uint64]实例,您必须使用强制转换

PS> ([uint64] ('1gb' / 1)).GetType().FullName
System.Int64
Run Code Online (Sandbox Code Playgroud)

请注意(...)计算周围的要求,[uint64]否则强制转换将'1gb'仅适用于(因此失败)。
或者,也('1gb' / [uint64] 1)可以工作。

笔记:

  • '1gb' - 0 也会起作用,
  • 不是 '1gb' * 1'(实际上是无操作)或'1gb' + 0(导致 string '1gb0',因为运算符*+带有字符串类型的 LHS 执行字符串操作(分别是复制和连接)。

PowerShell 中的自动字符串到数字转换数字文字

当 PowerShell 执行隐式数字转换时,包括在执行混合数字类型计算和解析源代码中的数字文字时,它会方便地自动选择“大”到足以容纳结果的数字类型

隐式字符串到数字转换中,PowerShell 可以方便地识别与源代码中数字文字支持的格式相同的格式

  • 号- 前缀(对于整数只):0x十六进制整数,且0b二进制整数(PowerShell的[核心] 7.0+)

  • 数字类型 后缀Lfor [long]( [System.Int64]) 和Dfor [decimal]( [System.Decimal]);例如,'1L' - 0产生 a [long]
    请注意,C#使用M代替D和代替用于D指定[System.Double];此外,C# 支持多个附加后缀。

    • PowerShell的[核心] 6.2+现在支持附加后缀Y[sbyte]), (UY),[byte]( ),S[int16] ),US或者,根据需要),和()。[uint16]U[uint32] [uint64]UL[uint64]

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

    • 您可以通过官方帮助主题about_Numeric_Literals关注未来的发展(如果有)。

  • 浮点表示,例如1.23(仅限十进制);请注意,PowerShell 只.将小数点识别为小数点,而与当前文化无关

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

  • 它自己的二进制乘数后缀, kb, mb, gb, tb, pb(对于乘数[math]::pow(2, 10)== 1024, [math]::pow(2, 20)== 1048576, ...); 例如,'1kb' - 1产量1023;请注意,这些后缀是特定于 PowerShell 的,因此 .NET 框架数字解析方法无法识别它们。

数字转换规则是复杂的,但这里有一些关键点

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

  • PowerShell从不自动选择无符号整数类型

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

    • 对于十进制整数文字/字符串,根据需要扩展超出整数类型到[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]由于是十六进制及释义因此,很多失败

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

  • PowerShell中似乎从来没有自动选择一个整数型[int]

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

    • 双方1 + [long] 1[long] 1 + 1产生[long](即使结果可能适合较小的类型)。
  • 也许出乎意料的是,对于大于任一操作数类型integer type can fit的计算结果PowerShell 自动选择浮点类型[double],即使结果可以适合更大的整数类型:

    • ([int]::maxvalue + 1).GetType().FullName产生System.Double(a [double]),即使结果适合[long]整数。
    • 但是,如果操作数之一是足够大的整数类型,则结果属于该类型:([int]::maxvalue + [long] 1).GetType().FullNameyields System.Int64(a [long])。
  • 在计算中涉及至少一种浮点类型总是导致[double],即使与整数类型混合或使用所有[float]操作数:

    • 1 / 1.0and 1.0 / 1and 1 / [float] 1and [float] 1 / 1and [float] 1 / [float] 1all 产生一个[double]
  • 源代码中不使用类型后缀的数字文字

    • 十进制整数文字被解释为以下类型中可以适合该值的最小类型:[int]> [long]> [decimal]> [double](!)

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

      • 0x1 产生一个 [int]

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

      • 0x100000000(1 多于可以放入[int](或[uint32])) 产生一个[long]

      • 0x10000000000000000(1 超过可以放入[long](或[uint64]))中断,因为[long]是支持的最大类型(“数字常量无效”)。

      • 要确保十六进制文字产生

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

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

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

    • 浮点指数符号文字(只能以十进制表示形式识别)总是被解释为 a[double],无论多小:

      • 1.0并且1e0都产生一个[double]

  • 很好的答案让我明白了很多,谢谢你花时间把它放在一起。 (2认同)

Sea*_*ean 6

您的问题是ToUint64不了解Powershell语法.你可以做到:

($MemoryFromString / 1GB) * 1GB
Run Code Online (Sandbox Code Playgroud)

因为$MemoryFromString将在分割之前转换其数值.

这是有效的,因为在分割时,Powershell尝试使用其规则将字符串转换为数字,而不是转换为.Net规则ToUInt64.作为转换的一部分,如果找到GB后缀并应用它来规则将"1GB"字符串扩展为1073741824

编辑:或者像PetSerAl指出的那样,你可以这样做:

($MemoryFromString / 1)
Run Code Online (Sandbox Code Playgroud)