Powershell 字符串格式在循环时无法添加十六进制前缀
Powershell String format fails to add hex prefix when looping
再见-
我正在使用 Powershell 7.2 通过硬件的 CLI 自动执行一些硬件配置。
我正在使用一个循环来生成包含“0x”前缀的字符串以表示十六进制字节,但有一个问题,即在第一次循环之后的任何连续迭代都不会打印“0x”前缀。
以下会产生问题:
function fTest($id)
{
foreach($n in @(1, 2, 3))
{
write-host $id.gettype()
write-host ("{0:x}" -f $id)
$id++
}
}
fTest 0x1a
实际输出:
System.Int32
0x1a
System.Int32
1b
System.Int32
1c
迭代 2 和 3 中省略了 0x
前缀。
- 为什么会这样?
- 什么是更正问题的干净方法?
我是 PowerShell 菜鸟,所以我很高兴收到完全不同方法的建议或示例。
在此先感谢您的帮助!
tl;dr
Type-constrain 您的 $p
参数 明确地 使其成为 数字 (整数),正如 Theo 所建议的那样:
function fTest($id)
-> function fTest([int] $id)
将 0x
前缀构建到传递给 -f
的格式字符串中:
"{0:x}" -f $id
-> '0x{0:x}' -f $id
基于有用的评论:
Why is this happening?
格式字符串{0:x}
,当应用于数字时,只会产生十六进制表示而没有 ]一个0x
前缀;例如:
PS> '{0:x}' -f 10
a # NOT '0xa'
如果操作数 不是 数字,则数字 :x
规范被 忽略 :
PS> '{0:x}' -f 'foo'
foo
您遇到的问题与 PowerShell 如何处理传递给非 type-constrained:
参数的参数有关
参数0x1a
不明确:它可能是一个数字 - 表示为十六进制常数0x1a
,相当于十进制 26
- 或 string.
- 虽然在表达式-解析模式中,这种歧义不会出现(字符串必须在那里被引用),它在argument- 解析模式,其中字符串周围的引号是可选的(除非字符串包含元字符)- 请参阅概念性 about_Parsing 主题。
PowerShell 在这种情况下所做的是创建 a hybrid 参数值:该值被解析为 number,但它在后台缓存其原始字符串表示,用于显示格式,例如:
PS> & { param($p) $p; $p.ToString() } 0x1a
0x1a # With default output formatting, the original string form is used.
26 # $p is an [int], so .ToString() yields its decimal representation
从 PowerShell 7.2.2 开始,令人惊讶且有问题的是,在 -f
的上下文中,string-formatting operator,例如 混合值被视为字符串,即使它self-reports被视为数字:
PS> & { param($p) $p.GetType().FullName; '{0:N2}' -f $p } 0x1a
System.Int32 # $p is of type [int] == System.Int32
0x1a # !! With -f $p is unexpectedly treated *as a string*,
# !! yielding the cached original string representation.
- 此意外行为已在 GitHub issue #17199 中报告。
Type-constraining 将这种混合参数传递给的参数,如顶部所示,避免了歧义:在调用时,参数被转换为参数类型的未包装实例(见下一点)。
至于为什么输出从第2次迭代开始改变:
在这种情况下,缓存的字符串表示是通过 [psobject]
存储在 $id
中的数字类型实例的不可见 [psobject]
包装器实现的。
当您通过递增操作 (++
) 更新此值时,[psobject]
包装器 丢失 ,并且变量更新为一个展开的数字(原始值 + 1)。
因此,从第 2 次迭代开始,$id
包含一个未包装的 [int]
实例,导致 {0:x}
数字格式被接受,因此产生一个十六进制表示 没有 0x
前缀。
第一次迭代产生 0x
前缀的唯一原因是它出现在参数的原始字符串表示中;如上所述,在这种情况下 numeric :x
格式说明符被 忽略 ,因为 -f
操作数是 (意外) 被视为 string.
再见-
我正在使用 Powershell 7.2 通过硬件的 CLI 自动执行一些硬件配置。 我正在使用一个循环来生成包含“0x”前缀的字符串以表示十六进制字节,但有一个问题,即在第一次循环之后的任何连续迭代都不会打印“0x”前缀。
以下会产生问题:
function fTest($id)
{
foreach($n in @(1, 2, 3))
{
write-host $id.gettype()
write-host ("{0:x}" -f $id)
$id++
}
}
fTest 0x1a
实际输出:
System.Int32
0x1a
System.Int32
1b
System.Int32
1c
迭代 2 和 3 中省略了 0x
前缀。
- 为什么会这样?
- 什么是更正问题的干净方法?
我是 PowerShell 菜鸟,所以我很高兴收到完全不同方法的建议或示例。
在此先感谢您的帮助!
tl;dr
Type-constrain 您的
$p
参数 明确地 使其成为 数字 (整数),正如 Theo 所建议的那样:function fTest($id)
->function fTest([int] $id)
将
0x
前缀构建到传递给-f
的格式字符串中:"{0:x}" -f $id
->'0x{0:x}' -f $id
基于有用的评论:
Why is this happening?
格式字符串
{0:x}
,当应用于数字时,只会产生十六进制表示而没有 ]一个0x
前缀;例如:PS> '{0:x}' -f 10 a # NOT '0xa'
如果操作数 不是 数字,则数字
:x
规范被 忽略 :PS> '{0:x}' -f 'foo' foo
您遇到的问题与 PowerShell 如何处理传递给非 type-constrained:
参数的参数有关参数
0x1a
不明确:它可能是一个数字 - 表示为十六进制常数0x1a
,相当于十进制26
- 或 string.- 虽然在表达式-解析模式中,这种歧义不会出现(字符串必须在那里被引用),它在argument- 解析模式,其中字符串周围的引号是可选的(除非字符串包含元字符)- 请参阅概念性 about_Parsing 主题。
PowerShell 在这种情况下所做的是创建 a hybrid 参数值:该值被解析为 number,但它在后台缓存其原始字符串表示,用于显示格式,例如:
PS> & { param($p) $p; $p.ToString() } 0x1a 0x1a # With default output formatting, the original string form is used. 26 # $p is an [int], so .ToString() yields its decimal representation
从 PowerShell 7.2.2 开始,令人惊讶且有问题的是,在
-f
的上下文中,string-formatting operator,例如 混合值被视为字符串,即使它self-reports被视为数字:PS> & { param($p) $p.GetType().FullName; '{0:N2}' -f $p } 0x1a System.Int32 # $p is of type [int] == System.Int32 0x1a # !! With -f $p is unexpectedly treated *as a string*, # !! yielding the cached original string representation.
- 此意外行为已在 GitHub issue #17199 中报告。
Type-constraining 将这种混合参数传递给的参数,如顶部所示,避免了歧义:在调用时,参数被转换为参数类型的未包装实例(见下一点)。
至于为什么输出从第2次迭代开始改变:
在这种情况下,缓存的字符串表示是通过
[psobject]
存储在$id
中的数字类型实例的不可见[psobject]
包装器实现的。当您通过递增操作 (
++
) 更新此值时,[psobject]
包装器 丢失 ,并且变量更新为一个展开的数字(原始值 + 1)。因此,从第 2 次迭代开始,
$id
包含一个未包装的[int]
实例,导致{0:x}
数字格式被接受,因此产生一个十六进制表示 没有0x
前缀。第一次迭代产生
0x
前缀的唯一原因是它出现在参数的原始字符串表示中;如上所述,在这种情况下 numeric:x
格式说明符被 忽略 ,因为-f
操作数是 (意外) 被视为 string.