我正在处理一个时间值,该时间值以T
开头,然后是一系列数字,后面紧跟着每个数字的单位。例如,8小时22分钟将作为T8H22M
,3小时2分钟1秒将作为T3H2M1S
。
我需要将这个编码的值拆分为单独的H/M/S列,但我在获取零以正常工作时遇到了问题。我使用的是另一个问题中的代码,这里有类似(但不完全相同(的要求。
此脚本:
Write-Host $('T8H22M' -split { [bool]($_ -as [double]) })
Write-Host $('T8H22M' -split { ! [bool]($_ -as [double]) })
Write-Host $('T8H0M' -split { [bool]($_ -as [double]) })
Write-Host $('T8H0M' -split { ! [bool]($_ -as [double]) })
Write-Host $('T0H' -split { $_ -eq '0' })
产生此输出:
T H M
8 22
T H0M
8
T H
正如你所看到的,任何时候数值为零,字符串都不会分裂。这是一个真正的问题,因为零时间作为T0H
出现,它不会使用上面的方法进行解析。
我如何修改上面的代码以同时拆分零值?
您可以使用正则表达式来提取值。例如:
'T3H2M1S','T8H22M','T8H0M','T0H' |
ForEach-Object {
if($_ -match '^T((?<hours>d+)H)*((?<minutes>d+)M)*((?<seconds>d+)S)*$') {
[PsCustomObject]@{
TimeString = $matches.0
Hours = [Int]$matches.hours
Minutes = [Int]$matches.minutes
Seconds = [Int]$matches.seconds
}
}
}
这为每个时间字符串生成一个对象,其中Hours
、Minutes
和Seconds
属性对应于该字符串的相关部分:
TimeString Hours Minutes Seconds
---------- ----- ------- -------
T3H2M1S 3 2 1
T8H22M 8 22 0
T8H0M 8 0 0
T0H 0 0 0
当然,您可以随意更改if
的内容来操作值,而不仅仅是创建一个对象——关键是RegEx应该为您正确地拆分它。
*-我说"应该",因为我只测试了你给出的示例字符串,所以一定要自己测试得更彻底
您拥有的时间值类似于ISO 8601持续时间格式,只是它们都缺少前导P
。
您可以使用.netSystem.Xml.XmlConvert
的ToTimeSpan()
方法,使用将这些转换为时间跨度
'T3H2M1S','T8H22M','T8H0M','T0H' | ForEach-Object {
[System.Xml.XmlConvert]::ToTimeSpan("P$_") # prepend a 'P'
}
返回TimeSpan对象数组
Days : 0
Hours : 8
Minutes : 22
Seconds : 0
Milliseconds : 0
Ticks : 301200000000
TotalDays : 0,348611111111111
TotalHours : 8,36666666666667
TotalMinutes : 502
TotalSeconds : 30120
TotalMilliseconds : 30120000
Days : 0
Hours : 8
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 288000000000
TotalDays : 0,333333333333333
TotalHours : 8
TotalMinutes : 480
TotalSeconds : 28800
TotalMilliseconds : 28800000
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 0
TotalDays : 0
TotalHours : 0
TotalMinutes : 0
TotalSeconds : 0
TotalMilliseconds : 0
现在,您可以使用任何属性进行格式化。
为了赞扬@boxdog和@Theo对实际问题的回答为什么缺少零和"我如何修改上面的代码以同时拆分零值">
引用<ScriptBlock>
参数
<ScriptBlock>
指定应用分隔符规则的表达式。这个表达式必须计算为$true
或$false
。封装脚本块在大括号中。
这里的要点是0
评估为$False
("falsy
"(:
if (0) { 'True' } else { 'False' }
False
if (1) { 'True' } else { 'False' }
True
[Bool]0
False
[Bool]1
True
换句话说,你需要将你的分裂表达式与$Null
进行比较,以获得你想要的:
Write-Host $('T8H22M' -split { $Null -ne ($_ -as [double]) })
T H M
Write-Host $('T8H22M' -split { $Null -eq ($_ -as [double]) })
8 22
Write-Host $('T8H0M' -split { $Null -ne ($_ -as [double]) })
T H M
Write-Host $('T8H0M' -split { $Null -eq ($_ -as [double]) })
8 0
无论如何,我建议你选择@boxdog或@Theo的解决方案。