如何从 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
,tb
、pb
(对于乘数 [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+ 中,您可以使用类型后缀
US
、U
或 UL
(见上文) 强制处理为无符号类型(正数);例如,0xffffffffffffffffU
- 对于十六进制 数字字面量 这可能是意想不到的;例如,
[uint32] 0xffffffff
失败 ,因为 0xffffffff
是 first - 隐含地 - 转换为 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+:根据需要使用类型后缀 us
、u
或 ul
;例如:0x8000us
-> 32768
([uint16]
), 0x80000000u
-> 2147483648
([uint32]
), 0x8000000000000000ul
-> 9223372036854775808
([uint64]
)
Binary integer 文字(PowerShell [Core] 7.0+)的解释方式与 十六进制个;例如,0b10000000000000000000000000000000
== 0x80000000
== -2147483648
([int]
)
Floating-point 或 指数符号 文字 (仅在 decimal 表示中被识别) 总是被解释为 [double]
,无论多小:
1.0
和 1e0
都产生 [double]
考虑以下 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
,tb
、pb
(对于乘数[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+ 中,您可以使用类型后缀
US
、U
或UL
(见上文) 强制处理为无符号类型(正数);例如,0xffffffffffffffffU
- 对于十六进制 数字字面量 这可能是意想不到的;例如,
[uint32] 0xffffffff
失败 ,因为0xffffffff
是 first - 隐含地 - 转换为 signed 类型[int32]
,它产生-1
,作为 signed 值,不能转换为 unsigned 输入[uint32]
. - 解决方法:
- 附加
L
以强制解释为[int64]
,这会产生预期的正值4294967295
,在这种情况下,转换为[uint32]
会成功。 - 该技术不适用于
0x7fffffffffffffff
([long]::maxvalue
) 以上的值,但是,在这种情况下,您可以使用 string 转换:[uint64] '0xffffffffffffffff'
- 附加
- 注意:在 PowerShell [Core] 6.2+ 中,您可以使用类型后缀
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
and1.0 / 1
and1 / [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+:根据需要使用类型后缀
us
、u
或ul
;例如:0x8000us
->32768
([uint16]
),0x80000000u
->2147483648
([uint32]
),0x8000000000000000ul
->9223372036854775808
([uint64]
)
Binary integer 文字(PowerShell [Core] 7.0+)的解释方式与 十六进制个;例如,
0b10000000000000000000000000000000
==0x80000000
==-2147483648
([int]
)Floating-point 或 指数符号 文字 (仅在 decimal 表示中被识别) 总是被解释为
[double]
,无论多小:1.0
和1e0
都产生[double]