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?
为了补充 肖恩的有用答案:
只有结果变量 ( [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 可以方便地识别与源代码中数字文字支持的格式相同的格式:
号-基 前缀(对于整数只):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从不自动选择无符号整数类型。
US,U或UL(见上文)强制处理为无符号类型(正数);例如,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]您的问题是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)
| 归档时间: |
|
| 查看次数: |
3976 次 |
| 最近记录: |