提问人:Peyre 提问时间:11/17/2023 最后编辑:Peyre 更新时间:11/18/2023 访问量:67
PowerShell,当有 2+ 个值时,从 [string[]] 参数剪裁的前导零
powershell, leading zero trimed from [string[]] parameters when there is 2+ values
问:
我有一个 cmdlet,它接受电话号码列表作为参数。某些电话号码的第一个字符为 0。当我只用一个数字调用函数时,字符串保持原样。当我用 2+ 数字调用函数时,前导零被修剪
function user {
[CmdletBinding()]
param (
[Parameter(mandatory,position=0)]
[string[]]
$numbers
)
process {
$numbers
$users = @{
'0600000001' = 'user1'
'0600000002' = 'user2'
}
foreach($key in $users.keys) {
if($numbers -contains $key) {
write-host $users[$key]
}
}
}
}
例如
[PS] D:\> user 0600000001
0600000001
user1
[PS] D:\> user 0600000002
0600000002
user2
但
[PS] D:> user 0600000001,0600000002
600000001
600000002
当然,如果我在数字周围加上引号,它会按预期工作
[PS] D:\> user '0600000001','0600000002'
0600000001
0600000002
user2
user1
但是该 cmdlet 不适合我的使用,用户非常热衷于忘记在参数周围加上引号。
我用谷歌搜索了一下,发现了很多关于 PS 修改字符串的帖子/文章,但找不到如何防止它的解决方案。
你有什么线索吗?
答:
我认为您观察到的行为是一个错误,此后在 GitHub 问题 #20717 中报告了该错误:
在参数(分析)模式下使用标量参数(单个值)时,当 PowerShell 的参数绑定器最初分析它可以分析为数字文本的内容时,它会这样做,即将参数转换为数字类型(如
[int]),
同时还保留原始字符串表示形式,以防目标命令最终不需要数字。示例包括 、 、 、 偶数 或(数字类型后缀)
0600000001
2.3
0xA
1e2
1l
1d
- 但是,与表达式模式不同的是,以数字开头或未解析为数字的标记仍为字符串 ()。
+
-
[string]
- 但是,与表达式模式不同的是,以数字开头或未解析为数字的标记仍为字符串 ()。
此行为是通过将生成的数字实例(例如类型)包装在缓存原始字符串表示形式的不可见
[psobject]
包装器中来实现的;后者可以通过调用 - 来检索,但不能通过可扩展字符串中的字符串插值来检索 ([int]
.psobject.ToString()
.ToString()
"..."
).psobject.ToString()
在以下情况下隐式调用:调用外部程序时,因为传递原始字符串表示形式很重要,因为该上下文中没有类型概念,因此将原始参数(如 into)转换为是不合适的。
0xA
10
在默认的显示格式设置期间。
当投射到
[string]
在数组参数中,即使没有充分的理由不对每个元素执行相同的包装(这在技术上是可行的,因为 PowerShell 数组是类型化的,即其元素可以存储任何类型的值)。
[object[]]
请注意,在您的调用中,不会在表达式(解析)模式下解析 - 它仍然在参数模式下解析,在该模式下,数组构造也受支持(除非在调用外部程序时,其中不存在数组的概念),元素的解析方式与单个参数模式参数相同。
user 0600000001,0600000002
0600000001,0600000002
,
例如,是 的全参数模式等价物
,即具有嵌套表达式的参数模式语句。Write-Output foo, bar
Write-Output ('foo', 'bar')
要简明扼要地演示问题,请执行以下操作:
& {
param($Value) # implicitly [object]-typed - see below for why
foreach ($v in $Value) {
[pscustomobject] @{
StringRepresentation = $v.ToString()
OriginalStringRepresentation = $v.psobject.ToString()
Type = $v.GetType()
IsPSObjectWrapped = $Value -is [psobject]
}
}
} 042
这将输出以下内容,显示参数被解析为 with value ,但包装在具有缓存的原始字符串表示形式的实例中:042
[int]
42
[psobject]
StringRepresentation OriginalStringRepresentation Type IsPSObjectWrapped
-------------------- ---------------------------- ---- -----------------
42 042 System.Int32 True
转换到此类参数的数组表明此包装已丢失:
传递而不是产生:042, 043, +44, -45
042
StringRepresentation OriginalStringRepresentation Type IsPSObjectWrapped
-------------------- ---------------------------- ---- -----------------
42 42 System.Int32 False
43 43 System.Int32 False
+44 +44 System.String False
-45 -45 System.String False
请注意 and 的原始字符串表示形式是如何丢失的,而 and 由于其前缀而被解析为字符串。042
043
+44
-45
注意:
示例脚本块使用非类型化(即隐式类型化参数),该参数可以在没有显式类型转换的情况下检查行为。
[object]
- 如果参数已声明为 (aka ),即使在单参数情况下,原始字符串表示也会丢失,这本身可以被视为一个错误。
[object[]]
[Array]
- 如果参数已声明为 (aka ),即使在单参数情况下,原始字符串表示也会丢失,这本身可以被视为一个错误。
使用类型化参数,如您的问题所示,它确实适用于单参数情况,但在多参数情况下会失败,因为在构造数组时原始字符串表示形式已经丢失,因为丢失发生在初始的幕后,必要的基于数组解析。
[string[]]
[string[]]
[object]
评论
[ValidatePattern()]
评论
ValueFromRemainingArguments